From 9abaf09a8587904204613da07df5826e8b3aac03 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Fri, 22 May 2026 02:07:54 -0700 Subject: [PATCH 01/17] Share pinterface calculation code with cppwinrt and precalc generic instantiations --- cppwinrt/code_writers.h | 41 +++++ cppwinrt/file_writers.h | 10 ++ cppwinrt/helpers.h | 225 +++++++++++++++++++++++ cppwinrt/winmd_signature.h | 356 +++++++++++++++++++++++++++++++++++++ natvis/type_resolver.cpp | 246 +------------------------ 5 files changed, 638 insertions(+), 240 deletions(-) create mode 100644 cppwinrt/winmd_signature.h diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index ab119ae89..c5b1184e3 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -537,6 +537,47 @@ namespace cppwinrt } } + static void write_generic_inst_specializations(writer& w, std::map const& instantiations) + { + if (instantiations.empty()) + { + return; + } + + w.write(R"( + // Pre-computed name_v and guid_v specializations for parameterized type instantiations. + // These avoid costly constexpr SHA1 computation at compile time. +)"); + + for (auto&& [cpp_name, info] : instantiations) + { + // name_v specialization: e.g., + // template <> inline constexpr auto name_v> + // = L"Windows.Foundation.Collections.IMap"; + w.write(R"( template <> inline constexpr auto& name_v<%> = L"%"; +)", + info.cpp_name, + info.winrt_name); + } + + for (auto&& [cpp_name, info] : instantiations) + { + auto& g = info.guid; + // guid_v specialization: e.g., + // template <> inline constexpr guid guid_v>{ 0x..., ... }; + w.write(" template <> inline constexpr guid guid_v<%>{ ", info.cpp_name); + 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]); + } + } + static void write_struct_category(writer& w, TypeDef const& type) { auto format = R"( template <> struct category<%>{ using type = struct_category<%>; }; diff --git a/cppwinrt/file_writers.h b/cppwinrt/file_writers.h index fd9833cb1..eb6be1760 100644 --- a/cppwinrt/file_writers.h +++ b/cppwinrt/file_writers.h @@ -116,6 +116,16 @@ namespace cppwinrt w.write_each(members.interfaces); w.write_each(members.delegates); w.write_each(members.classes); + + // Collect and emit explicit name_v/guid_v specializations for concrete + // parameterized type instantiations (e.g., IMap). + // This avoids costly constexpr SHA1 GUID computation at compile time. + { + std::map instantiations; + collect_generic_instantiations(w, members, instantiations); + write_generic_inst_specializations(w, instantiations); + } + w.write_each(members.interfaces); w.write_each(members.delegates); w.write_each(members.interfaces); diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index 2dc152a74..bace238bb 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1,7 +1,16 @@ #pragma once +#include "winmd_signature.h" + namespace cppwinrt { + using winmd_signature::guid_value; + using winmd_signature::extract_guid; + using winmd_signature::format_guid_signature; + using winmd_signature::compute_guid_from_signature; + using winmd_signature::type_arg_stack; + using winmd_signature::signature_builder; + static auto get_start_time() { return std::chrono::high_resolution_clock::now(); @@ -1145,4 +1154,220 @@ namespace cppwinrt return settings.component_filter.includes(class_name); } + + struct generic_inst_info + { + std::string cpp_name; // C++ name, produced by the writer at the end + std::string winrt_name; // WinRT name, e.g. "Windows.Foundation.Collections.IMap" + guid_value guid; + }; + + // ---- winrt_name_builder: builds WinRT display names from metadata ---- + struct winrt_name_builder + { + static std::string get_name(GenericTypeInstSig const& type, type_arg_stack const& resolve = {}) + { + auto generic_type = type.GenericType(); + auto [ns, name] = get_type_namespace_and_name(generic_type); + auto tick = name.rfind('`'); + if (tick != std::string_view::npos) + name = name.substr(0, tick); + + std::string result = std::string(ns) + "." + std::string(name) + "<"; + bool first = true; + for (auto&& arg : type.GenericArgs()) + { + if (!first) result += ", "; + first = false; + result += get_arg_name(arg, resolve); + } + result += ">"; + return result; + } + + private: + static std::string get_element_name(ElementType t) + { + switch (t) + { + case ElementType::Boolean: return "Boolean"; + case ElementType::Char: return "Char16"; + case ElementType::I1: return "Int8"; + case ElementType::U1: return "UInt8"; + case ElementType::I2: return "Int16"; + case ElementType::U2: return "UInt16"; + case ElementType::I4: return "Int32"; + case ElementType::U4: return "UInt32"; + case ElementType::I8: return "Int64"; + case ElementType::U8: return "UInt64"; + case ElementType::R4: return "Single"; + case ElementType::R8: return "Double"; + case ElementType::String: return "String"; + case ElementType::Object: return "Object"; + default: return {}; + } + } + + static std::string get_typedef_name(TypeDef const& td) + { + return std::string(td.TypeNamespace()) + "." + std::string(td.TypeName()); + } + + static std::string get_arg_name(TypeSig const& sig, type_arg_stack const& resolve) + { + return call(sig.Type(), + [](ElementType t) -> std::string { return get_element_name(t); }, + [&](GenericTypeIndex idx) -> std::string + { + if (!resolve.empty() && idx.index < resolve.back().size()) + { + type_arg_stack parent_resolve(resolve.begin(), resolve.end() - 1); + return get_arg_name(resolve.back()[idx.index], parent_resolve); + } + return {}; + }, + [](GenericMethodTypeIndex) -> std::string { return {}; }, + [&](coded_index const& t) -> std::string + { + switch (t.type()) + { + case TypeDefOrRef::TypeDef: return get_typedef_name(t.TypeDef()); + case TypeDefOrRef::TypeRef: + { + auto tr = t.TypeRef(); + if (tr.TypeNamespace() == "System" && tr.TypeName() == "Guid") return "Guid"; + return get_typedef_name(find_required(tr)); + } + default: return get_name(t.TypeSpec().Signature().GenericTypeInst(), resolve); + } + }, + [&](GenericTypeInstSig const& t) -> std::string { return get_name(t, resolve); }); + } + }; + + // ---- Recursive collection of concrete generic instantiations ---- + // Walks InterfaceImpl chains, carrying concrete TypeSig args to resolve GenericTypeIndex. + // All computation stays in metadata-land; the C++ name is only produced at the end via the writer. + + static void collect_generic_inst_recursive( + writer& w, + GenericTypeInstSig const& type, + type_arg_stack const& outer_resolve, + std::map& instantiations) + { + // Build the resolution context for this instantiation: + // The args of 'type' may themselves contain GenericTypeIndex references + // that need resolving through outer_resolve. + // Collect the concrete TypeSig args after resolution. + std::vector concrete_args; + for (auto&& arg : type.GenericArgs()) + { + if (auto* idx = std::get_if(&arg.Type())) + { + // Resolve through the outer stack + if (outer_resolve.empty() || idx->index >= outer_resolve.back().size()) + { + return; // Can't resolve — open generic, skip + } + concrete_args.push_back(outer_resolve.back()[idx->index]); + } + else + { + concrete_args.push_back(arg); + } + } + + // Build a resolution stack with our concrete args appended + type_arg_stack resolve = outer_resolve; + resolve.push_back(concrete_args); + + // Compute the type signature and GUID using our resolving signature_builder + auto sig = signature_builder::get_signature(type, outer_resolve); + auto guid = compute_guid_from_signature(sig); + auto winrt_name = winrt_name_builder::get_name(type, outer_resolve); + + // Get the C++ name from the writer. The writer's generic_param_stack already has + // the outer context pushed by our caller, so write_temp resolves GenericTypeIndex. + auto cpp_name = w.write_temp("%", type); + + if (instantiations.count(cpp_name)) + { + return; + } + + generic_inst_info info; + info.cpp_name = cpp_name; + info.winrt_name = winrt_name; + info.guid = guid; + instantiations[cpp_name] = std::move(info); + + // Recurse into generic args that are themselves generic instantiations + for (auto&& arg : concrete_args) + { + if (auto* spec = std::get_if>(&arg.Type())) + { + if (spec->type() == TypeDefOrRef::TypeSpec) + { + collect_generic_inst_recursive(w, spec->TypeSpec().Signature().GenericTypeInst(), outer_resolve, instantiations); + } + } + else if (auto* inst = std::get_if(&arg.Type())) + { + collect_generic_inst_recursive(w, *inst, outer_resolve, instantiations); + } + } + + // Recurse into the generic type's required interfaces (e.g., IMap : IIterable, etc.) + auto base_type = find_required(type.GenericType()); + + // Push the writer's generic_param_stack for write_temp in nested calls + auto writer_guard = w.push_generic_params(type); + + for (auto&& impl : base_type.InterfaceImpl()) + { + auto iface = impl.Interface(); + if (iface.type() == TypeDefOrRef::TypeSpec) + { + // This TypeSpec may have GenericTypeIndex references to base_type's params. + // 'resolve' has our concrete args at the back, so signature_builder can resolve them. + collect_generic_inst_recursive(w, iface.TypeSpec().Signature().GenericTypeInst(), resolve, instantiations); + } + } + } + + // Entry point: collect all concrete generic instantiations from a namespace's members. + static void collect_generic_instantiations( + writer& w, + cache::namespace_members const& members, + std::map& instantiations) + { + auto collect_from_type = [&](TypeDef const& type) + { + for (auto&& impl : type.InterfaceImpl()) + { + auto iface = impl.Interface(); + if (iface.type() == TypeDefOrRef::TypeSpec) + { + collect_generic_inst_recursive(w, iface.TypeSpec().Signature().GenericTypeInst(), {}, instantiations); + } + } + }; + + for (auto&& type : members.classes) + { + collect_from_type(type); + for (auto&& base : get_bases(type)) + { + collect_from_type(base); + } + } + + for (auto&& type : members.interfaces) + { + if (empty(type.GenericParam())) + { + collect_from_type(type); + } + } + } } diff --git a/cppwinrt/winmd_signature.h b/cppwinrt/winmd_signature.h new file mode 100644 index 000000000..cb191ef95 --- /dev/null +++ b/cppwinrt/winmd_signature.h @@ -0,0 +1,356 @@ +#pragma once + +// Shared utilities for computing WinRT parameterized interface GUIDs from metadata. +// Used by both cppwinrt.exe (code generator) and the natvis visualizer. +// Only depends on winmd_reader.h — no dependency on the cppwinrt writer or natvis types. + +namespace winmd_signature +{ + using namespace winmd::reader; + + // ---- visit helper (works in both cppwinrt.exe and natvis contexts) ---- + template struct overloaded : T... { using T::operator()...; }; + template overloaded(T...) -> overloaded; + + template + auto call(V&& variant, C&&...c) + { + return std::visit(overloaded{ std::forward(c)... }, std::forward(variant)); + } + + // ---- GUID value type (plain struct, no dependency on winrt::guid) ---- + struct guid_value + { + std::uint32_t Data1; + std::uint16_t Data2; + std::uint16_t Data3; + std::uint8_t Data4[8]; + }; + + // ---- Extract a GUID from a TypeDef's GuidAttribute ---- + inline guid_value extract_guid(TypeDef const& type) + { + auto attribute = get_attribute(type, "Windows.Foundation.Metadata", "GuidAttribute"); + if (!attribute) + { + winmd::impl::throw_invalid("'Windows.Foundation.Metadata.GuidAttribute' attribute for type '", + type.TypeNamespace(), ".", type.TypeName(), "' not found"); + } + auto args = attribute.Value().FixedArgs(); + return + { + std::get(std::get(args[0].value).value), + std::get(std::get(args[1].value).value), + std::get(std::get(args[2].value).value), + { + std::get(std::get(args[3].value).value), + std::get(std::get(args[4].value).value), + std::get(std::get(args[5].value).value), + std::get(std::get(args[6].value).value), + std::get(std::get(args[7].value).value), + std::get(std::get(args[8].value).value), + std::get(std::get(args[9].value).value), + std::get(std::get(args[10].value).value) + } + }; + } + + // ---- Format a GUID as a lowercase signature string: {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} ---- + inline std::string format_guid_signature(guid_value const& g) + { + char buf[64]; + sprintf_s(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%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]); + return buf; + } + + // ---- SHA1 computation ---- + struct sha1_context + { + static constexpr std::uint32_t K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; + + static std::uint32_t rotl(std::uint8_t bits, std::uint32_t word) + { + return (word << bits) | (word >> (32 - bits)); + } + + static std::array process_block(std::uint8_t const* input, std::size_t start, std::array hash) + { + std::array W{}; + for (std::size_t t = 0; t < 16; ++t) + { + W[t] = static_cast(input[start + t * 4]) << 24 | + static_cast(input[start + t * 4 + 1]) << 16 | + static_cast(input[start + t * 4 + 2]) << 8 | + static_cast(input[start + t * 4 + 3]); + } + for (std::size_t t = 16; t < 80; ++t) + { + W[t] = rotl(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); + } + + auto A = hash[0], B = hash[1], C = hash[2], D = hash[3], E = hash[4]; + std::uint32_t temp; + for (std::size_t t = 0; t < 20; ++t) + { + temp = rotl(5, A) + ((B & C) ^ ((~B) & D)) + E + W[t] + K[0]; + E = D; D = C; C = rotl(30, B); B = A; A = temp; + } + for (std::size_t t = 20; t < 40; ++t) + { + temp = rotl(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; D = C; C = rotl(30, B); B = A; A = temp; + } + for (std::size_t t = 40; t < 60; ++t) + { + temp = rotl(5, A) + ((B & C) ^ (B & D) ^ (C & D)) + E + W[t] + K[2]; + E = D; D = C; C = rotl(30, B); B = A; A = temp; + } + for (std::size_t t = 60; t < 80; ++t) + { + temp = rotl(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; D = C; C = rotl(30, B); B = A; A = temp; + } + + return { hash[0] + A, hash[1] + B, hash[2] + C, hash[3] + D, hash[4] + E }; + } + + static std::array compute(std::vector const& input) + { + std::array hash{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; + std::size_t i = 0; + + while (i + 64 <= input.size()) + { + hash = process_block(input.data(), i, hash); + i += 64; + } + + auto bit_length = input.size() * 8; + auto remainder_size = input.size() % 64; + + std::array final_block{}; + std::copy(input.begin() + i, input.end(), final_block.begin()); + final_block[remainder_size] = 0x80; + + std::size_t block_count; + if (remainder_size + 1 + 8 <= 64) + { + block_count = 64; + } + else + { + block_count = 128; + } + + for (int b = 7; b >= 0; --b) + { + final_block[block_count - 8 + (7 - b)] = static_cast((bit_length >> (b * 8)) & 0xFF); + } + + hash = process_block(final_block.data(), 0, hash); + if (block_count == 128) + { + hash = process_block(final_block.data(), 64, hash); + } + + std::array result{}; + for (std::size_t idx = 0; idx < 20; ++idx) + { + result[idx] = static_cast(hash[idx >> 2] >> (8 * (3 - (idx & 0x03)))); + } + return result; + } + }; + + // ---- Compute a UUID v5 GUID from a WinRT type signature string ---- + inline guid_value compute_guid_from_signature(std::string const& sig) + { + constexpr std::uint8_t namespace_bytes[] = + { + // {d57af411-737b-c042-abae-878b1e16adee} in little-endian byte order + 0x11, 0xf4, 0x7a, 0xd5, + 0x7b, 0x73, + 0x42, 0xc0, + 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee + }; + + std::vector buffer(std::begin(namespace_bytes), std::end(namespace_bytes)); + buffer.insert(buffer.end(), sig.begin(), sig.end()); + + auto hash = sha1_context::compute(buffer); + + guid_value result; + result.Data1 = static_cast(hash[0]) << 24 | static_cast(hash[1]) << 16 | + static_cast(hash[2]) << 8 | static_cast(hash[3]); + result.Data2 = static_cast(hash[4]) << 8 | hash[5]; + result.Data3 = static_cast(hash[6]) << 8 | hash[7]; + std::copy(hash.begin() + 8, hash.begin() + 16, result.Data4); + + // Endian swap + result.Data1 = ((result.Data1 & 0xFF000000) >> 24) | ((result.Data1 & 0x00FF0000) >> 8) | + ((result.Data1 & 0x0000FF00) << 8) | ((result.Data1 & 0x000000FF) << 24); + result.Data2 = static_cast((result.Data2 >> 8) | (result.Data2 << 8)); + result.Data3 = static_cast((result.Data3 >> 8) | (result.Data3 << 8)); + + // Set version=5 and variant + result.Data3 = static_cast((result.Data3 & 0x0FFF) | (5 << 12)); + result.Data4[0] = static_cast((result.Data4[0] & 0x3F) | 0x80); + + return result; + } + + // ---- Resolution context for substituting GenericTypeIndex with concrete TypeSig values ---- + using type_arg_stack = std::vector>; + + // ---- signature_builder: computes WinRT type signature strings from metadata ---- + // Accepts an optional resolution stack to substitute GenericTypeIndex. + // Operates entirely on metadata types (TypeDef, TypeRef, TypeSpec, TypeSig). + struct signature_builder + { + static std::string get_signature(coded_index const& type, type_arg_stack const& resolve = {}) + { + switch (type.type()) + { + case TypeDefOrRef::TypeDef: + return get_signature(type.TypeDef()); + case TypeDefOrRef::TypeRef: + return get_signature(type.TypeRef()); + default: + return get_signature(type.TypeSpec().Signature().GenericTypeInst(), resolve); + } + } + + static std::string get_signature(GenericTypeInstSig const& type, type_arg_stack const& resolve = {}) + { + std::string sig = "pinterface(" + get_guid_string(type.GenericType()); + for (auto&& arg : type.GenericArgs()) + { + sig += ";"; + sig += get_signature(arg, resolve); + } + sig += ")"; + return sig; + } + + private: + static std::string get_full_name(TypeDef const& type) + { + return std::string(type.TypeNamespace()) + "." + std::string(type.TypeName()); + } + + static std::string get_default_interface_signature(TypeDef const& type) + { + for (auto&& impl : type.InterfaceImpl()) + { + if (get_attribute(impl, "Windows.Foundation.Metadata", "DefaultAttribute")) + { + return "rc(" + get_full_name(type) + ";" + get_signature(impl.Interface()) + ")"; + } + } + return {}; + } + + static std::string get_enum_signature(TypeDef const& type) + { + bool is_flags = static_cast(get_attribute(type, "System", "FlagsAttribute")); + return "enum(" + get_full_name(type) + ";" + (is_flags ? "u4" : "i4") + ")"; + } + + static std::string get_struct_signature(TypeDef const& type) + { + std::string sig = "struct(" + get_full_name(type); + for (auto& field : type.FieldList()) + { + sig += ";"; + sig += get_signature(field.Signature().Type()); + } + sig += ")"; + return sig; + } + + static std::string get_guid_string(TypeDef const& type) + { + return format_guid_signature(extract_guid(type)); + } + + static std::string get_guid_string(coded_index const& type) + { + switch (type.type()) + { + case TypeDefOrRef::TypeDef: + return get_guid_string(type.TypeDef()); + case TypeDefOrRef::TypeRef: + return get_guid_string(find_required(type.TypeRef())); + default: + return get_signature(type.TypeSpec().Signature().GenericTypeInst()); + } + } + + static std::string get_element_signature(ElementType t) + { + switch (t) + { + case ElementType::Boolean: return "b1"; + case ElementType::Char: return "c2"; + case ElementType::I1: return "i1"; + case ElementType::U1: return "u1"; + case ElementType::I2: return "i2"; + case ElementType::U2: return "u2"; + case ElementType::I4: return "i4"; + case ElementType::U4: return "u4"; + case ElementType::I8: return "i8"; + case ElementType::U8: return "u8"; + case ElementType::R4: return "f4"; + case ElementType::R8: return "f8"; + case ElementType::String: return "string"; + case ElementType::Object: return "cinterface(IInspectable)"; + default: return {}; + } + } + + static std::string get_signature(TypeSig::value_type const& type, type_arg_stack const& resolve = {}) + { + return call(type, + [&](ElementType t) -> std::string { return get_element_signature(t); }, + [&](GenericTypeIndex idx) -> std::string + { + if (!resolve.empty() && idx.index < resolve.back().size()) + { + type_arg_stack parent_resolve(resolve.begin(), resolve.end() - 1); + return get_signature(resolve.back()[idx.index], parent_resolve); + } + return {}; + }, + [](GenericMethodTypeIndex) -> std::string { return {}; }, + [&](auto&& t) -> std::string { return get_signature(t, resolve); }); + } + + static std::string get_signature(TypeDef const& type) + { + switch (get_category(type)) + { + case category::interface_type: return get_guid_string(type); + case category::class_type: return get_default_interface_signature(type); + case category::enum_type: return get_enum_signature(type); + case category::struct_type: return get_struct_signature(type); + case category::delegate_type: return "delegate(" + get_guid_string(type) + ")"; + default: return {}; + } + } + + static std::string get_signature(TypeRef const& type) + { + if (type.TypeNamespace() == "System" && type.TypeName() == "Guid") + return "g16"; + return get_signature(find_required(type)); + } + + static std::string get_signature(TypeSig const& sig, type_arg_stack const& resolve = {}) + { + return get_signature(sig.Type(), resolve); + } + }; +} diff --git a/natvis/type_resolver.cpp b/natvis/type_resolver.cpp index de8af71f4..c7c9a891c 100644 --- a/natvis/type_resolver.cpp +++ b/natvis/type_resolver.cpp @@ -1,4 +1,5 @@ #include "pch.h" +#include "winmd_signature.h" using namespace winrt; using namespace winmd::reader; @@ -7,47 +8,14 @@ using namespace Microsoft::VisualStudio::Debugger; static std::map, std::pair> _cache; -template -static bool has_attribute(T const& row, std::string_view const& type_namespace, std::string_view const& type_name) noexcept +static guid to_winrt_guid(winmd_signature::guid_value const& g) { - return static_cast(get_attribute(row, type_namespace, type_name)); -} - -template -static auto call(V&& variant, C&& ...call) -{ - return std::visit(overloaded{ std::forward(call)... }, std::forward(variant)); -} - -static std::string get_full_name(TypeDef const& type) -{ - return std::string(type.TypeNamespace()) + "." + std::string(type.TypeName()); + return { 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] } }; } static guid get_guid(TypeDef const& type) { - auto attribute = get_attribute(type, "Windows.Foundation.Metadata", "GuidAttribute"); - if (!attribute) - { - throw_invalid("'Windows.Foundation.Metadata.GuidAttribute' attribute for type '", get_full_name(type), "' not found"); - } - auto args = attribute.Value().FixedArgs(); - return - { - std::get(std::get(args[0].value).value), - std::get(std::get(args[1].value).value), - std::get(std::get(args[2].value).value), - { - std::get(std::get(args[3].value).value), - std::get(std::get(args[4].value).value), - std::get(std::get(args[5].value).value), - std::get(std::get(args[6].value).value), - std::get(std::get(args[7].value).value), - std::get(std::get(args[8].value).value), - std::get(std::get(args[9].value).value), - std::get(std::get(args[10].value).value) - } - }; + return to_winrt_guid(winmd_signature::extract_guid(type)); } static std::wstring format_guid(guid guid) @@ -70,212 +38,10 @@ static std::wstring format_guid(guid guid) return guid_str; } -static auto get_default_interface(TypeDef const& type) -{ - auto impls = type.InterfaceImpl(); - for (auto&& impl : impls) - { - if (has_attribute(impl, "Windows.Foundation.Metadata"sv, "DefaultAttribute"sv)) - { - return impl.Interface(); - } - } - throw_invalid("Type '", get_full_name(type), "' does not have a default interface"); -} - -struct signature_generator -{ - static std::string get_signature(coded_index const& type) - { - switch (type.type()) - { - case TypeDefOrRef::TypeDef: - return get_signature(type.TypeDef()); - case TypeDefOrRef::TypeRef: - return get_signature(type.TypeRef()); - default: //case TypeDefOrRef::TypeSpec: - return get_signature(type.TypeSpec().Signature().GenericTypeInst()); - } - } - - static std::string get_signature(GenericTypeInstSig const& type) - { - std::string sig = "pinterface(" + get_guid_signature(type.GenericType()); - for (auto&& arg : type.GenericArgs()) - { - sig += ";"; - sig += get_signature(arg); - } - sig += ")"; - return sig; - } - -private: - static std::string get_class_signature(TypeDef const& type) - { - return std::string("rc(") + get_full_name(type) + ";" + get_signature(get_default_interface(type)) + ")"; - } - - static auto get_enum_signature(TypeDef const& type) - { - bool is_flags = has_attribute(type, "System"sv, "FlagsAttribute"sv); - return "enum(" + get_full_name(type) + ";" + (is_flags ? "u4" : "i4") + ")"; - } - - static std::string get_struct_signature(TypeDef const& type) - { - std::string sig = "struct(" + get_full_name(type); - for (auto& field : type.FieldList()) - { - sig += ";"; - sig += get_signature(field.Signature().Type()); - } - sig += ")"; - return sig; - } - - static std::string get_guid_signature(TypeDef const& type) - { - auto guid = get_guid(type); - std::string guid_str(70, '?'); - int count = sprintf_s(guid_str.data(), guid_str.size() + 1, - "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - guid.Data1, - guid.Data2, - guid.Data3, - guid.Data4[0], - guid.Data4[1], - guid.Data4[2], - guid.Data4[3], - guid.Data4[4], - guid.Data4[5], - guid.Data4[6], - guid.Data4[7]); - guid_str.resize(count); - return guid_str; - } - - static std::string get_guid_signature(coded_index const& type) - { - switch (type.type()) - { - case TypeDefOrRef::TypeDef: - return get_guid_signature(type.TypeDef()); - case TypeDefOrRef::TypeRef: - return get_guid_signature(find_required(type.TypeRef())); - default: //case TypeDefOrRef::TypeSpec: - return get_signature(type.TypeSpec().Signature().GenericTypeInst()); - } - } - - static std::string get_signature(TypeSig::value_type const& type) - { - return call(type, [&](ElementType type) -> std::string - { - switch (type) - { - case ElementType::Boolean: return "b1"; - case ElementType::Char: return "c2"; - case ElementType::I1: return "i1"; - case ElementType::U1: return "u1"; - case ElementType::I2: return "i2"; - case ElementType::U2: return "u2"; - case ElementType::I4: return "i4"; - case ElementType::U4: return "u4"; - case ElementType::I8: return "i8"; - case ElementType::U8: return "u8"; - case ElementType::R4: return "f4"; - case ElementType::R8: return "f8"; - case ElementType::String: return "string"; - case ElementType::Object: return "cinterface(IInspectable)"; - default: assert(false); return ""; - } - }, - [&](auto&& type) - { - return get_signature(type); - }); - } - - static std::string get_signature(TypeDef const& type) - { - switch (get_category(type)) - { - case category::interface_type: - return get_guid_signature(type); - case category::class_type: - return get_class_signature(type); - case category::enum_type: - return get_enum_signature(type); - case category::struct_type: - return get_struct_signature(type); - default: //case category::delegate_type: - return "delegate(" + get_guid_signature(type) + ")"; - } - } - - static std::string get_signature(TypeRef const& type) - { - if (type.TypeNamespace() == "System" && type.TypeName() == "Guid") - { - return "g16"; - } - return get_signature(find_required(type)); - } - - static std::string get_signature(TypeSig const& signature) - { - return get_signature(signature.Type()); - } -}; - -using namespace winrt::impl; - -static auto calculate_sha1(std::vector const& input) -{ - auto input_size = input.size(); - - std::array intermediate_hash{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; - uint32_t i = 0; - while (i + 64 <= input_size) - { - intermediate_hash = process_msg_block(input.data(), i, intermediate_hash); - i += 64; - } - - auto length = size_to_bytes(input_size * 8); - auto remainder_size = (input_size % 64) + 1; - if (remainder_size + 8 <= 64) - { - std::array remainder{}; - std::copy(input.begin() + i, input.end(), remainder.begin()); - remainder[remainder_size - 1] = 0x80; - std::copy(length.begin(), length.end(), remainder.end() - 8); - intermediate_hash = process_msg_block(remainder.data(), 0, intermediate_hash); - } - else - { - std::array remainder{}; - std::copy(input.begin() + i, input.end(), remainder.begin()); - remainder[remainder_size - 1] = 0x80; - std::copy(length.begin(), length.end(), remainder.end() - 8); - intermediate_hash = process_msg_block(remainder.data(), 0, intermediate_hash); - intermediate_hash = process_msg_block(remainder.data(), 64, intermediate_hash); - } - - return get_result(intermediate_hash); -} - static guid generate_guid(GenericTypeInstSig const& type) { - constexpr guid namespace_guid = { 0xd57af411, 0x737b, 0xc042,{ 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee } }; - constexpr auto namespace_bytes = winrt::impl::to_array(namespace_guid); - - std::vector buffer{ namespace_bytes.begin(), namespace_bytes.end() }; - auto sig = signature_generator::get_signature(type); - buffer.insert(buffer.end(), sig.begin(), sig.end()); - - return set_named_guid_fields(endian_swap(to_guid(calculate_sha1(buffer)))); + auto sig = winmd_signature::signature_builder::get_signature(type); + return to_winrt_guid(winmd_signature::compute_guid_from_signature(sig)); } std::pair ResolveTypeInterface(DkmProcess* process, winmd::reader::TypeSig const& typeSig) From b9e9b02af80cf05a20762b565019b618d892a795 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Fri, 22 May 2026 02:15:30 -0700 Subject: [PATCH 02/17] Replace sprintf with a quick lookup table for hex digits --- cppwinrt/winmd_signature.h | 45 +++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/cppwinrt/winmd_signature.h b/cppwinrt/winmd_signature.h index cb191ef95..6775e79d8 100644 --- a/cppwinrt/winmd_signature.h +++ b/cppwinrt/winmd_signature.h @@ -56,14 +56,47 @@ namespace winmd_signature } // ---- Format a GUID as a lowercase signature string: {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} ---- + namespace impl + { + inline void write_hex(char*& p, std::uint8_t value) + { + static constexpr char digits[] = "0123456789abcdef"; + *p++ = digits[value >> 4]; + *p++ = digits[value & 0xF]; + } + + inline void write_hex(char*& p, std::uint16_t value) + { + write_hex(p, static_cast(value >> 8)); + write_hex(p, static_cast(value & 0xFF)); + } + + inline void write_hex(char*& p, std::uint32_t value) + { + write_hex(p, static_cast(value >> 16)); + write_hex(p, static_cast(value & 0xFFFF)); + } + } + inline std::string format_guid_signature(guid_value const& g) { - char buf[64]; - sprintf_s(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%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]); - return buf; + // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} = 38 chars + null + char buf[39]; + char* p = buf; + *p++ = '{'; + impl::write_hex(p, g.Data1); *p++ = '-'; + impl::write_hex(p, g.Data2); *p++ = '-'; + impl::write_hex(p, g.Data3); *p++ = '-'; + impl::write_hex(p, g.Data4[0]); + impl::write_hex(p, g.Data4[1]); *p++ = '-'; + impl::write_hex(p, g.Data4[2]); + impl::write_hex(p, g.Data4[3]); + impl::write_hex(p, g.Data4[4]); + impl::write_hex(p, g.Data4[5]); + impl::write_hex(p, g.Data4[6]); + impl::write_hex(p, g.Data4[7]); + *p++ = '}'; + return { buf, static_cast(p - buf) }; } // ---- SHA1 computation ---- From e8b716753917c1380af8cfdd7383c14274a7b72d Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 27 May 2026 13:22:38 -0700 Subject: [PATCH 03/17] Minor cleanup --- cppwinrt/code_writers.h | 11 +++-------- cppwinrt/helpers.h | 25 +++++++------------------ 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index c5b1184e3..532f93467 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -549,22 +549,17 @@ namespace cppwinrt // These avoid costly constexpr SHA1 computation at compile time. )"); - for (auto&& [cpp_name, info] : instantiations) + for (auto&& [winrt_name, info] : instantiations) { - // name_v specialization: e.g., - // template <> inline constexpr auto name_v> - // = L"Windows.Foundation.Collections.IMap"; w.write(R"( template <> inline constexpr auto& name_v<%> = L"%"; )", info.cpp_name, - info.winrt_name); + winrt_name); } - for (auto&& [cpp_name, info] : instantiations) + for (auto&& [winrt_name, info] : instantiations) { auto& g = info.guid; - // guid_v specialization: e.g., - // template <> inline constexpr guid guid_v>{ 0x..., ... }; w.write(" template <> inline constexpr guid guid_v<%>{ ", info.cpp_name); 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, diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index bace238bb..f91b4f84d 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1157,8 +1157,7 @@ namespace cppwinrt struct generic_inst_info { - std::string cpp_name; // C++ name, produced by the writer at the end - std::string winrt_name; // WinRT name, e.g. "Windows.Foundation.Collections.IMap" + std::string cpp_name; guid_value guid; }; @@ -1247,7 +1246,6 @@ namespace cppwinrt // ---- Recursive collection of concrete generic instantiations ---- // Walks InterfaceImpl chains, carrying concrete TypeSig args to resolve GenericTypeIndex. - // All computation stays in metadata-land; the C++ name is only produced at the end via the writer. static void collect_generic_inst_recursive( writer& w, @@ -1281,25 +1279,16 @@ namespace cppwinrt type_arg_stack resolve = outer_resolve; resolve.push_back(concrete_args); - // Compute the type signature and GUID using our resolving signature_builder - auto sig = signature_builder::get_signature(type, outer_resolve); - auto guid = compute_guid_from_signature(sig); + // Use winrt_name as the dedup key. Only do expensive work if this is a new entry. auto winrt_name = winrt_name_builder::get_name(type, outer_resolve); - - // Get the C++ name from the writer. The writer's generic_param_stack already has - // the outer context pushed by our caller, so write_temp resolves GenericTypeIndex. - auto cpp_name = w.write_temp("%", type); - - if (instantiations.count(cpp_name)) + auto [it, inserted] = instantiations.try_emplace(std::move(winrt_name)); + if (!inserted) { return; } - generic_inst_info info; - info.cpp_name = cpp_name; - info.winrt_name = winrt_name; - info.guid = guid; - instantiations[cpp_name] = std::move(info); + it->second.cpp_name = w.write_temp("%", type); + it->second.guid = compute_guid_from_signature(signature_builder::get_signature(type, outer_resolve)); // Recurse into generic args that are themselves generic instantiations for (auto&& arg : concrete_args) @@ -1320,7 +1309,7 @@ namespace cppwinrt // Recurse into the generic type's required interfaces (e.g., IMap : IIterable, etc.) auto base_type = find_required(type.GenericType()); - // Push the writer's generic_param_stack for write_temp in nested calls + // Push the writer's generic_param_stack so write_temp resolves GenericTypeIndex in nested calls auto writer_guard = w.push_generic_params(type); for (auto&& impl : base_type.InterfaceImpl()) From f5bab1f85b6428ebd4562cc08c89bdf3f14f1935 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 27 May 2026 15:15:53 -0700 Subject: [PATCH 04/17] Fix some calculations. Wrap guid_v and name_v specializations in preprocessor guard to avoid duplicate specialization definition errors. --- cppwinrt/code_writers.h | 24 ++++++++++--- cppwinrt/helpers.h | 73 +++++++++++++++++++++++++++++++++++--- cppwinrt/winmd_signature.h | 6 ---- 3 files changed, 88 insertions(+), 15 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 532f93467..43664a0c0 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -537,6 +537,20 @@ namespace cppwinrt } } + static std::string make_pinterface_guard(std::string_view const& winrt_name) + { + std::string guard = "WINRT_IMPL_PINTERFACE_"; + guard.reserve(guard.size() + winrt_name.size()); + for (char c : winrt_name) + { + if (c == '.' || c == '<' || c == '>' || c == ',' || c == ' ' || c == '`') + guard += '_'; + else + guard += c; + } + return guard; + } + static void write_generic_inst_specializations(writer& w, std::map const& instantiations) { if (instantiations.empty()) @@ -551,15 +565,14 @@ namespace cppwinrt for (auto&& [winrt_name, info] : instantiations) { + auto guard = make_pinterface_guard(winrt_name); + auto& g = info.guid; + w.write("#ifndef %\n", guard); + w.write("#define %\n", guard); w.write(R"( template <> inline constexpr auto& name_v<%> = L"%"; )", info.cpp_name, winrt_name); - } - - for (auto&& [winrt_name, info] : instantiations) - { - auto& g = info.guid; w.write(" template <> inline constexpr guid guid_v<%>{ ", info.cpp_name); 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, @@ -570,6 +583,7 @@ namespace cppwinrt 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("#endif // %\n", guard); } } diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index f91b4f84d..4bc3f5b74 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1168,9 +1168,6 @@ namespace cppwinrt { auto generic_type = type.GenericType(); auto [ns, name] = get_type_namespace_and_name(generic_type); - auto tick = name.rfind('`'); - if (tick != std::string_view::npos) - name = name.substr(0, tick); std::string result = std::string(ns) + "." + std::string(name) + "<"; bool first = true; @@ -1245,7 +1242,45 @@ namespace cppwinrt }; // ---- Recursive collection of concrete generic instantiations ---- - // Walks InterfaceImpl chains, carrying concrete TypeSig args to resolve GenericTypeIndex. + // Walks InterfaceImpl chains and method signatures, carrying concrete TypeSig args to resolve GenericTypeIndex. + + static void collect_generic_inst_recursive( + writer& w, + GenericTypeInstSig const& type, + type_arg_stack const& outer_resolve, + std::map& instantiations); + + // Helper: if a TypeSig contains a GenericTypeInstSig (directly or via TypeSpec), collect it. + static void collect_from_type_sig( + writer& w, + TypeSig const& sig, + type_arg_stack const& resolve, + std::map& instantiations) + { + call(sig.Type(), + [](ElementType) {}, + [&](GenericTypeIndex idx) + { + // Resolve and recurse if the resolved type is itself a generic instantiation + if (!resolve.empty() && idx.index < resolve.back().size()) + { + type_arg_stack parent_resolve(resolve.begin(), resolve.end() - 1); + collect_from_type_sig(w, resolve.back()[idx.index], parent_resolve, instantiations); + } + }, + [](GenericMethodTypeIndex) {}, + [&](coded_index const& t) + { + if (t.type() == TypeDefOrRef::TypeSpec) + { + collect_generic_inst_recursive(w, t.TypeSpec().Signature().GenericTypeInst(), resolve, instantiations); + } + }, + [&](GenericTypeInstSig const& t) + { + collect_generic_inst_recursive(w, t, resolve, instantiations); + }); + } static void collect_generic_inst_recursive( writer& w, @@ -1322,6 +1357,22 @@ namespace cppwinrt collect_generic_inst_recursive(w, iface.TypeSpec().Signature().GenericTypeInst(), resolve, instantiations); } } + + // Walk method signatures to find generic types in return types and parameters. + // E.g., IIterable.First() returns IIterator, so IIterable> + // produces IIterator> which needs name_v/guid_v. + for (auto&& method : base_type.MethodList()) + { + auto sig = method.Signature(); + if (sig.ReturnType()) + { + collect_from_type_sig(w, sig.ReturnType().Type(), resolve, instantiations); + } + for (auto&& param : sig.Params()) + { + collect_from_type_sig(w, param.Type(), resolve, instantiations); + } + } } // Entry point: collect all concrete generic instantiations from a namespace's members. @@ -1340,6 +1391,20 @@ namespace cppwinrt collect_generic_inst_recursive(w, iface.TypeSpec().Signature().GenericTypeInst(), {}, instantiations); } } + + // Also walk the type's own methods for concrete generic return/param types. + for (auto&& method : type.MethodList()) + { + auto sig = method.Signature(); + if (sig.ReturnType()) + { + collect_from_type_sig(w, sig.ReturnType().Type(), {}, instantiations); + } + for (auto&& param : sig.Params()) + { + collect_from_type_sig(w, param.Type(), {}, instantiations); + } + } }; for (auto&& type : members.classes) diff --git a/cppwinrt/winmd_signature.h b/cppwinrt/winmd_signature.h index 6775e79d8..80a9675df 100644 --- a/cppwinrt/winmd_signature.h +++ b/cppwinrt/winmd_signature.h @@ -222,12 +222,6 @@ namespace winmd_signature result.Data3 = static_cast(hash[6]) << 8 | hash[7]; std::copy(hash.begin() + 8, hash.begin() + 16, result.Data4); - // Endian swap - result.Data1 = ((result.Data1 & 0xFF000000) >> 24) | ((result.Data1 & 0x00FF0000) >> 8) | - ((result.Data1 & 0x0000FF00) << 8) | ((result.Data1 & 0x000000FF) << 24); - result.Data2 = static_cast((result.Data2 >> 8) | (result.Data2 << 8)); - result.Data3 = static_cast((result.Data3 >> 8) | (result.Data3 << 8)); - // Set version=5 and variant result.Data3 = static_cast((result.Data3 & 0x0FFF) | (5 << 12)); result.Data4[0] = static_cast((result.Data4[0] & 0x3F) | 0x80); From 7c631fe873b2b3a3f73b61d47502a8baf53b9ce2 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 27 May 2026 15:25:07 -0700 Subject: [PATCH 05/17] Precompute "standard" IReference pinterfaces --- strings/base_reference_produce.h | 190 +++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/strings/base_reference_produce.h b/strings/base_reference_produce.h index abffb3384..f20fd0281 100644 --- a/strings/base_reference_produce.h +++ b/strings/base_reference_produce.h @@ -393,6 +393,196 @@ WINRT_EXPORT namespace winrt::impl static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateRectArray(value); } using itf = Windows::Foundation::IReferenceArray; }; + + // Pre-computed pinterface GUIDs for standard IReference types. + // These avoid costly constexpr SHA1 computation at compile time. +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt8_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt8_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0xE5198CC8,0x2873,0x55F5,{ 0xB0,0xA1,0x84,0xFF,0x9E,0x4A,0xAD,0x62 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int16_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int16_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x6EC9E41B,0x6709,0x5647,{ 0x99,0x18,0xA1,0x27,0x01,0x10,0xFC,0x4E } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt16_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt16_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x5AB7D2C3,0x6B62,0x5E71,{ 0xA4,0xB6,0x2D,0x49,0xC4,0xF2,0x38,0xFD } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int32_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int32_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x548CEFBD,0xBC8A,0x5FA0,{ 0x8D,0xF2,0x95,0x74,0x40,0xFC,0x8B,0xF4 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt32_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt32_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x513EF3AF,0xE784,0x5325,{ 0xA9,0x1E,0x97,0xC2,0xB8,0x11,0x1C,0xF3 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int64_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int64_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x4DDA9E24,0xE69F,0x5C6A,{ 0xA0,0xA6,0x93,0x42,0x73,0x65,0xAF,0x2A } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt64_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt64_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x6755E376,0x53BB,0x568B,{ 0xA1,0x1D,0x17,0x23,0x98,0x68,0x30,0x9E } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Single_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Single_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x719CC2BA,0x3E76,0x5DEF,{ 0x9F,0x1A,0x38,0xD8,0x5A,0x14,0x5E,0xA8 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Double_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Double_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x2F2D6C29,0x5473,0x5F3E,{ 0x92,0xE7,0x96,0x57,0x2B,0xB9,0x90,0xE2 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Char16_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Char16_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0xFB393EF3,0xBBAC,0x5BD5,{ 0x91,0x44,0x84,0xF2,0x35,0x76,0xF4,0x15 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Boolean_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Boolean_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x3C00FD60,0x2950,0x5939,{ 0xA2,0x1A,0x2D,0x12,0xC5,0xA0,0x1B,0x8A } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_String_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_String_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0xFD416DFB,0x2A07,0x52EB,{ 0xAA,0xE3,0xDF,0xCE,0x14,0x11,0x6C,0x05 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Guid_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Guid_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x7D50F649,0x632C,0x51F9,{ 0x84,0x9A,0xEE,0x49,0x42,0x89,0x33,0xEA } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_DateTime_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_DateTime_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x5541D8A7,0x497C,0x5AA4,{ 0x86,0xFC,0x77,0x13,0xAD,0xBF,0x2A,0x2C } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_TimeSpan_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_TimeSpan_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x604D0C4C,0x91DE,0x5C2A,{ 0x93,0x5F,0x36,0x2F,0x13,0xEA,0xF8,0x00 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Point_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Point_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x84F14C22,0xA00A,0x5272,{ 0x8D,0x3D,0x82,0x11,0x2E,0x66,0xDF,0x00 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Size_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Size_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x61723086,0x8E53,0x5276,{ 0x9F,0x36,0x2A,0x4B,0xB9,0x3E,0x2B,0x75 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Rect_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Rect_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; + template <> inline constexpr guid guid_v>{ 0x80423F11,0x054F,0x5EAC,{ 0xAF,0xD3,0x63,0xB6,0xCE,0x15,0xE7,0x7B } }; +#endif + + // Pre-computed pinterface GUIDs for standard IReferenceArray types. +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt8_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt8_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x2AF22683,0x3734,0x56D0,{ 0xA6,0x0E,0x68,0x8C,0xC8,0x5D,0x16,0x19 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int16_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int16_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x912F8FD7,0xADC0,0x5D60,{ 0xA8,0x96,0x7E,0xD7,0x60,0x89,0xCC,0x5B } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt16_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt16_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x6624A2DD,0x83F7,0x519C,{ 0x9D,0x55,0xBB,0x1F,0x65,0x60,0x45,0x6B } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int32_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int32_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0xA6D080A5,0xB087,0x5BC2,{ 0x9A,0x9F,0x5C,0xD6,0x87,0xB4,0xD1,0xF7 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt32_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt32_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x97374B68,0xEB87,0x56CC,{ 0xB1,0x8E,0x27,0xEF,0x0F,0x9C,0xFC,0x0C } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int64_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int64_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x6E333271,0x2E2A,0x5955,{ 0x87,0x90,0x83,0x6C,0x76,0xEE,0x53,0xB6 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt64_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt64_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x38B60434,0xD67C,0x523E,{ 0x9D,0x0E,0x24,0xD6,0x43,0x41,0x10,0x73 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Single_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Single_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x6AB1EA83,0xCB41,0x5F99,{ 0x92,0xCC,0x23,0xBD,0x43,0x36,0xA1,0xFB } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Double_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Double_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0xD301F253,0xE0A3,0x5D2B,{ 0x9A,0x41,0xA4,0xD6,0x2B,0xEC,0x46,0x23 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Char16_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Char16_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0xA4095AAB,0xEB7D,0x5782,{ 0x8F,0xAD,0x16,0x09,0xDE,0xA2,0x49,0xAD } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Boolean_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Boolean_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0xE8E72666,0x48CC,0x593F,{ 0xBA,0x85,0x26,0x63,0x49,0x69,0x56,0xE3 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_String_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_String_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x0385688E,0xE3C7,0x5C5E,{ 0xA3,0x89,0x55,0x24,0xED,0xE3,0x49,0xF1 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Object_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Object_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x9CD7A84F,0x0C80,0x59C5,{ 0xB4,0x4E,0x97,0x78,0x41,0xBB,0x43,0xD9 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Guid_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Guid_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0xEECF9838,0xC1C2,0x5B4A,{ 0x97,0x6F,0xCE,0xC2,0x61,0xAE,0x1D,0x55 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_DateTime_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_DateTime_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x1B8E9594,0x588E,0x5A07,{ 0x9E,0x65,0x07,0x31,0xA4,0xC9,0xA2,0xDB } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_TimeSpan_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_TimeSpan_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0xAD73197D,0x2CFA,0x57A6,{ 0x89,0x93,0x9F,0xAC,0x40,0xFE,0xB7,0x91 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Point_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Point_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x39313214,0x5C7D,0x599D,{ 0xAE,0x5A,0x17,0xD9,0xD6,0x49,0x22,0x58 } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Size_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Size_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x3B40E9D4,0xE0C3,0x56F6,{ 0xB8,0x8B,0xE5,0x05,0xEB,0x73,0x75,0x7B } }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Rect_ +#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Rect_ + template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; + template <> inline constexpr guid guid_v>{ 0x8A444256,0xD661,0x5E9A,{ 0xA7,0x2B,0xD8,0xF1,0xD7,0x96,0x2D,0x0C } }; +#endif } WINRT_EXPORT namespace winrt::Windows::Foundation From 765f429addd181db275e8469dc0d3895235281b9 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 27 May 2026 16:57:04 -0700 Subject: [PATCH 06/17] Fix shift-left underflow --- cppwinrt/winmd_signature.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cppwinrt/winmd_signature.h b/cppwinrt/winmd_signature.h index 80a9675df..681df4178 100644 --- a/cppwinrt/winmd_signature.h +++ b/cppwinrt/winmd_signature.h @@ -161,7 +161,7 @@ namespace winmd_signature i += 64; } - auto bit_length = input.size() * 8; + auto bit_length = static_cast(input.size()) * 8; auto remainder_size = input.size() % 64; std::array final_block{}; @@ -203,7 +203,7 @@ namespace winmd_signature { constexpr std::uint8_t namespace_bytes[] = { - // {d57af411-737b-c042-abae-878b1e16adee} in little-endian byte order + // {11f47ad5-7b73-42c0-abae-878b1e16adee} in big-endian byte order (RFC 4122) 0x11, 0xf4, 0x7a, 0xd5, 0x7b, 0x73, 0x42, 0xc0, From 41e5bc0972b0b10332380f8c44780f7835a16956 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 28 May 2026 12:23:16 -0700 Subject: [PATCH 07/17] Specialize pinterface_guid instead of guid_v. Friendlier to modules. Add unit tests. --- cppwinrt/code_writers.h | 37 +- cppwinrt/file_writers.h | 18 +- strings/base_identity.h | 1 + strings/base_reference_produce.h | 389 +++++++++--------- test/test/pinterface_guid_precomputed.cpp | 132 ++++++ test/test/test.vcxproj | 1 + .../pinterface_guid_precomputed.cpp | 119 ++++++ .../test_cpp20_module.vcxproj | 1 + 8 files changed, 488 insertions(+), 210 deletions(-) create mode 100644 test/test/pinterface_guid_precomputed.cpp create mode 100644 test/test_cpp20_module/pinterface_guid_precomputed.cpp diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 43664a0c0..d1794cf96 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -537,13 +537,13 @@ namespace cppwinrt } } - static std::string make_pinterface_guard(std::string_view const& winrt_name) + static std::string make_pinterface_guard(std::string_view const& cpp_name) { - std::string guard = "WINRT_IMPL_PINTERFACE_"; - guard.reserve(guard.size() + winrt_name.size()); - for (char c : winrt_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 == ' ' || c == '`') + if (c == ':' || c == '<' || c == '>' || c == ',' || c == ' ') guard += '_'; else guard += c; @@ -558,22 +558,27 @@ namespace cppwinrt 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). w.write(R"( - // Pre-computed name_v and guid_v specializations for parameterized type instantiations. - // These avoid costly constexpr SHA1 computation at compile time. +extern "C++" +{ +namespace winrt::impl +{ )"); for (auto&& [winrt_name, info] : instantiations) { - auto guard = make_pinterface_guard(winrt_name); + auto guard = make_pinterface_guard(info.cpp_name); auto& g = info.guid; w.write("#ifndef %\n", guard); w.write("#define %\n", guard); - w.write(R"( template <> inline constexpr auto& name_v<%> = L"%"; -)", - info.cpp_name, - winrt_name); - w.write(" template <> inline constexpr guid guid_v<%>{ ", info.cpp_name); + w.write(" template <> struct pinterface_guid<%>\n", info.cpp_name); + w.write(" {\n"); + w.write(" static constexpr bool precomputed = true;\n"); + w.write(" static constexpr guid value{ "); 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], @@ -583,8 +588,14 @@ namespace cppwinrt 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"); w.write("#endif // %\n", guard); } + + w.write(R"( +} // winrt::impl +} // extern "C++" +)"); } static void write_struct_category(writer& w, TypeDef const& type) diff --git a/cppwinrt/file_writers.h b/cppwinrt/file_writers.h index eb6be1760..bd37d8a92 100644 --- a/cppwinrt/file_writers.h +++ b/cppwinrt/file_writers.h @@ -117,21 +117,21 @@ namespace cppwinrt w.write_each(members.delegates); w.write_each(members.classes); - // Collect and emit explicit name_v/guid_v specializations for concrete - // parameterized type instantiations (e.g., IMap). - // This avoids costly constexpr SHA1 GUID computation at compile time. - { - std::map instantiations; - collect_generic_instantiations(w, members, instantiations); - write_generic_inst_specializations(w, instantiations); - } - w.write_each(members.interfaces); w.write_each(members.delegates); w.write_each(members.interfaces); w.write_each(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 instantiations; + collect_generic_instantiations(w, members, instantiations); + write_generic_inst_specializations(w, instantiations); + } + write_close_file_guard(w); w.swap(); write_preamble(w); diff --git a/strings/base_identity.h b/strings/base_identity.h index 7c61c83e2..07f99a1c5 100644 --- a/strings/base_identity.h +++ b/strings/base_identity.h @@ -453,6 +453,7 @@ WINRT_EXPORT namespace winrt::impl template struct pinterface_guid { + static constexpr bool precomputed = false; #ifdef _MSC_VER #pragma warning(suppress: 4307) #endif diff --git a/strings/base_reference_produce.h b/strings/base_reference_produce.h index f20fd0281..d2c70521c 100644 --- a/strings/base_reference_produce.h +++ b/strings/base_reference_produce.h @@ -394,195 +394,208 @@ WINRT_EXPORT namespace winrt::impl using itf = Windows::Foundation::IReferenceArray; }; - // Pre-computed pinterface GUIDs for standard IReference types. + // Pre-computed pinterface_guid specializations for standard IReference and IReferenceArray types. // These avoid costly constexpr SHA1 computation at compile time. -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt8_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt8_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0xE5198CC8,0x2873,0x55F5,{ 0xB0,0xA1,0x84,0xFF,0x9E,0x4A,0xAD,0x62 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int16_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int16_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x6EC9E41B,0x6709,0x5647,{ 0x99,0x18,0xA1,0x27,0x01,0x10,0xFC,0x4E } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt16_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt16_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x5AB7D2C3,0x6B62,0x5E71,{ 0xA4,0xB6,0x2D,0x49,0xC4,0xF2,0x38,0xFD } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int32_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int32_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x548CEFBD,0xBC8A,0x5FA0,{ 0x8D,0xF2,0x95,0x74,0x40,0xFC,0x8B,0xF4 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt32_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt32_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x513EF3AF,0xE784,0x5325,{ 0xA9,0x1E,0x97,0xC2,0xB8,0x11,0x1C,0xF3 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int64_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Int64_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x4DDA9E24,0xE69F,0x5C6A,{ 0xA0,0xA6,0x93,0x42,0x73,0x65,0xAF,0x2A } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt64_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_UInt64_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x6755E376,0x53BB,0x568B,{ 0xA1,0x1D,0x17,0x23,0x98,0x68,0x30,0x9E } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Single_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Single_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x719CC2BA,0x3E76,0x5DEF,{ 0x9F,0x1A,0x38,0xD8,0x5A,0x14,0x5E,0xA8 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Double_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Double_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x2F2D6C29,0x5473,0x5F3E,{ 0x92,0xE7,0x96,0x57,0x2B,0xB9,0x90,0xE2 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Char16_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Char16_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0xFB393EF3,0xBBAC,0x5BD5,{ 0x91,0x44,0x84,0xF2,0x35,0x76,0xF4,0x15 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Boolean_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Boolean_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x3C00FD60,0x2950,0x5939,{ 0xA2,0x1A,0x2D,0x12,0xC5,0xA0,0x1B,0x8A } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_String_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_String_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0xFD416DFB,0x2A07,0x52EB,{ 0xAA,0xE3,0xDF,0xCE,0x14,0x11,0x6C,0x05 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Guid_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Guid_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x7D50F649,0x632C,0x51F9,{ 0x84,0x9A,0xEE,0x49,0x42,0x89,0x33,0xEA } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_DateTime_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_DateTime_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x5541D8A7,0x497C,0x5AA4,{ 0x86,0xFC,0x77,0x13,0xAD,0xBF,0x2A,0x2C } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_TimeSpan_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_TimeSpan_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x604D0C4C,0x91DE,0x5C2A,{ 0x93,0x5F,0x36,0x2F,0x13,0xEA,0xF8,0x00 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Point_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Point_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x84F14C22,0xA00A,0x5272,{ 0x8D,0x3D,0x82,0x11,0x2E,0x66,0xDF,0x00 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Size_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Size_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x61723086,0x8E53,0x5276,{ 0x9F,0x36,0x2A,0x4B,0xB9,0x3E,0x2B,0x75 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Rect_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReference_1_Windows_Foundation_Rect_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReference`1"; - template <> inline constexpr guid guid_v>{ 0x80423F11,0x054F,0x5EAC,{ 0xAF,0xD3,0x63,0xB6,0xCE,0x15,0xE7,0x7B } }; -#endif - - // Pre-computed pinterface GUIDs for standard IReferenceArray types. -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt8_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt8_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x2AF22683,0x3734,0x56D0,{ 0xA6,0x0E,0x68,0x8C,0xC8,0x5D,0x16,0x19 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int16_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int16_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x912F8FD7,0xADC0,0x5D60,{ 0xA8,0x96,0x7E,0xD7,0x60,0x89,0xCC,0x5B } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt16_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt16_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x6624A2DD,0x83F7,0x519C,{ 0x9D,0x55,0xBB,0x1F,0x65,0x60,0x45,0x6B } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int32_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int32_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0xA6D080A5,0xB087,0x5BC2,{ 0x9A,0x9F,0x5C,0xD6,0x87,0xB4,0xD1,0xF7 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt32_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt32_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x97374B68,0xEB87,0x56CC,{ 0xB1,0x8E,0x27,0xEF,0x0F,0x9C,0xFC,0x0C } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int64_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Int64_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x6E333271,0x2E2A,0x5955,{ 0x87,0x90,0x83,0x6C,0x76,0xEE,0x53,0xB6 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt64_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_UInt64_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x38B60434,0xD67C,0x523E,{ 0x9D,0x0E,0x24,0xD6,0x43,0x41,0x10,0x73 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Single_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Single_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x6AB1EA83,0xCB41,0x5F99,{ 0x92,0xCC,0x23,0xBD,0x43,0x36,0xA1,0xFB } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Double_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Double_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0xD301F253,0xE0A3,0x5D2B,{ 0x9A,0x41,0xA4,0xD6,0x2B,0xEC,0x46,0x23 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Char16_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Char16_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0xA4095AAB,0xEB7D,0x5782,{ 0x8F,0xAD,0x16,0x09,0xDE,0xA2,0x49,0xAD } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Boolean_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Boolean_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0xE8E72666,0x48CC,0x593F,{ 0xBA,0x85,0x26,0x63,0x49,0x69,0x56,0xE3 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_String_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_String_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x0385688E,0xE3C7,0x5C5E,{ 0xA3,0x89,0x55,0x24,0xED,0xE3,0x49,0xF1 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Object_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Object_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x9CD7A84F,0x0C80,0x59C5,{ 0xB4,0x4E,0x97,0x78,0x41,0xBB,0x43,0xD9 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Guid_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Guid_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0xEECF9838,0xC1C2,0x5B4A,{ 0x97,0x6F,0xCE,0xC2,0x61,0xAE,0x1D,0x55 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_DateTime_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_DateTime_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x1B8E9594,0x588E,0x5A07,{ 0x9E,0x65,0x07,0x31,0xA4,0xC9,0xA2,0xDB } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_TimeSpan_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_TimeSpan_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0xAD73197D,0x2CFA,0x57A6,{ 0x89,0x93,0x9F,0xAC,0x40,0xFE,0xB7,0x91 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Point_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Point_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x39313214,0x5C7D,0x599D,{ 0xAE,0x5A,0x17,0xD9,0xD6,0x49,0x22,0x58 } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Size_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Size_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x3B40E9D4,0xE0C3,0x56F6,{ 0xB8,0x8B,0xE5,0x05,0xEB,0x73,0x75,0x7B } }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Rect_ -#define WINRT_IMPL_PINTERFACE_Windows_Foundation_IReferenceArray_1_Windows_Foundation_Rect_ - template <> inline constexpr auto& name_v> = L"Windows.Foundation.IReferenceArray`1"; - template <> inline constexpr guid guid_v>{ 0x8A444256,0xD661,0x5E9A,{ 0xA7,0x2B,0xD8,0xF1,0xD7,0x96,0x2D,0x0C } }; -#endif + // Wrapped in extern "C++" so that identical specializations across modules merge. + // #ifndef guards match those emitted by the code generator, preventing redefinition + // when both base_reference_produce.h and a generated .0.h define the same specialization. +} // winrt::impl + +extern "C++" +{ +namespace winrt::impl +{ +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint8_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint8_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xE5198CC8,0x2873,0x55F5,{ 0xB0,0xA1,0x84,0xFF,0x9E,0x4A,0xAD,0x62 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int16_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int16_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x6EC9E41B,0x6709,0x5647,{ 0x99,0x18,0xA1,0x27,0x01,0x10,0xFC,0x4E } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint16_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint16_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x5AB7D2C3,0x6B62,0x5E71,{ 0xA4,0xB6,0x2D,0x49,0xC4,0xF2,0x38,0xFD } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int32_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int32_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x548CEFBD,0xBC8A,0x5FA0,{ 0x8D,0xF2,0x95,0x74,0x40,0xFC,0x8B,0xF4 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint32_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint32_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x513EF3AF,0xE784,0x5325,{ 0xA9,0x1E,0x97,0xC2,0xB8,0x11,0x1C,0xF3 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int64_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int64_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x4DDA9E24,0xE69F,0x5C6A,{ 0xA0,0xA6,0x93,0x42,0x73,0x65,0xAF,0x2A } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint64_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint64_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x6755E376,0x53BB,0x568B,{ 0xA1,0x1D,0x17,0x23,0x98,0x68,0x30,0x9E } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_float_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_float_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x719CC2BA,0x3E76,0x5DEF,{ 0x9F,0x1A,0x38,0xD8,0x5A,0x14,0x5E,0xA8 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_double_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_double_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x2F2D6C29,0x5473,0x5F3E,{ 0x92,0xE7,0x96,0x57,0x2B,0xB9,0x90,0xE2 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_char16_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_char16_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xFB393EF3,0xBBAC,0x5BD5,{ 0x91,0x44,0x84,0xF2,0x35,0x76,0xF4,0x15 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_bool_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_bool_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x3C00FD60,0x2950,0x5939,{ 0xA2,0x1A,0x2D,0x12,0xC5,0xA0,0x1B,0x8A } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__hstring_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__hstring_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xFD416DFB,0x2A07,0x52EB,{ 0xAA,0xE3,0xDF,0xCE,0x14,0x11,0x6C,0x05 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__guid_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__guid_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x7D50F649,0x632C,0x51F9,{ 0x84,0x9A,0xEE,0x49,0x42,0x89,0x33,0xEA } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__DateTime_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__DateTime_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x5541D8A7,0x497C,0x5AA4,{ 0x86,0xFC,0x77,0x13,0xAD,0xBF,0x2A,0x2C } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__TimeSpan_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__TimeSpan_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x604D0C4C,0x91DE,0x5C2A,{ 0x93,0x5F,0x36,0x2F,0x13,0xEA,0xF8,0x00 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Point_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Point_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x84F14C22,0xA00A,0x5272,{ 0x8D,0x3D,0x82,0x11,0x2E,0x66,0xDF,0x00 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Size_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Size_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x61723086,0x8E53,0x5276,{ 0x9F,0x36,0x2A,0x4B,0xB9,0x3E,0x2B,0x75 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Rect_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Rect_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x80423F11,0x054F,0x5EAC,{ 0xAF,0xD3,0x63,0xB6,0xCE,0x15,0xE7,0x7B } }; }; +#endif + +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint8_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint8_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x2AF22683,0x3734,0x56D0,{ 0xA6,0x0E,0x68,0x8C,0xC8,0x5D,0x16,0x19 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int16_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int16_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x912F8FD7,0xADC0,0x5D60,{ 0xA8,0x96,0x7E,0xD7,0x60,0x89,0xCC,0x5B } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint16_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint16_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x6624A2DD,0x83F7,0x519C,{ 0x9D,0x55,0xBB,0x1F,0x65,0x60,0x45,0x6B } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int32_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int32_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xA6D080A5,0xB087,0x5BC2,{ 0x9A,0x9F,0x5C,0xD6,0x87,0xB4,0xD1,0xF7 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint32_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint32_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x97374B68,0xEB87,0x56CC,{ 0xB1,0x8E,0x27,0xEF,0x0F,0x9C,0xFC,0x0C } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int64_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int64_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x6E333271,0x2E2A,0x5955,{ 0x87,0x90,0x83,0x6C,0x76,0xEE,0x53,0xB6 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint64_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint64_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x38B60434,0xD67C,0x523E,{ 0x9D,0x0E,0x24,0xD6,0x43,0x41,0x10,0x73 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_float_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_float_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x6AB1EA83,0xCB41,0x5F99,{ 0x92,0xCC,0x23,0xBD,0x43,0x36,0xA1,0xFB } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_double_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_double_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xD301F253,0xE0A3,0x5D2B,{ 0x9A,0x41,0xA4,0xD6,0x2B,0xEC,0x46,0x23 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_char16_t_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_char16_t_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xA4095AAB,0xEB7D,0x5782,{ 0x8F,0xAD,0x16,0x09,0xDE,0xA2,0x49,0xAD } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_bool_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_bool_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xE8E72666,0x48CC,0x593F,{ 0xBA,0x85,0x26,0x63,0x49,0x69,0x56,0xE3 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__hstring_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__hstring_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x0385688E,0xE3C7,0x5C5E,{ 0xA3,0x89,0x55,0x24,0xED,0xE3,0x49,0xF1 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__IInspectable_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__IInspectable_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x9CD7A84F,0x0C80,0x59C5,{ 0xB4,0x4E,0x97,0x78,0x41,0xBB,0x43,0xD9 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__guid_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__guid_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xEECF9838,0xC1C2,0x5B4A,{ 0x97,0x6F,0xCE,0xC2,0x61,0xAE,0x1D,0x55 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__DateTime_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__DateTime_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x1B8E9594,0x588E,0x5A07,{ 0x9E,0x65,0x07,0x31,0xA4,0xC9,0xA2,0xDB } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__TimeSpan_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__TimeSpan_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0xAD73197D,0x2CFA,0x57A6,{ 0x89,0x93,0x9F,0xAC,0x40,0xFE,0xB7,0x91 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Point_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Point_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x39313214,0x5C7D,0x599D,{ 0xAE,0x5A,0x17,0xD9,0xD6,0x49,0x22,0x58 } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Size_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Size_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x3B40E9D4,0xE0C3,0x56F6,{ 0xB8,0x8B,0xE5,0x05,0xEB,0x73,0x75,0x7B } }; }; +#endif +#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Rect_ +#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Rect_ + template <> struct pinterface_guid> + { static constexpr bool precomputed = true; static constexpr guid value{ 0x8A444256,0xD661,0x5E9A,{ 0xA7,0x2B,0xD8,0xF1,0xD7,0x96,0x2D,0x0C } }; }; +#endif +} // winrt::impl +} // extern "C++" + +namespace winrt::impl +{ } WINRT_EXPORT namespace winrt::Windows::Foundation diff --git a/test/test/pinterface_guid_precomputed.cpp b/test/test/pinterface_guid_precomputed.cpp new file mode 100644 index 000000000..e41d2a02c --- /dev/null +++ b/test/test/pinterface_guid_precomputed.cpp @@ -0,0 +1,132 @@ +#include "pch.h" + +// Validate that pre-computed pinterface_guid specializations: +// 1. Have the precomputed flag set to true +// 2. Produce GUID values matching the algorithmic SHA-1 computation +// +// Tests cover both hand-written specializations (IReference/IReferenceArray +// in base_reference_produce.h) and code-generated specializations discovered +// from Windows SDK metadata (IMap, IIterable, TypedEventHandler, etc.). + +using namespace winrt; +using namespace winrt::impl; +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Collections; + +namespace +{ + constexpr bool equal(guid const& left, guid const& right) noexcept + { + return left.Data1 == right.Data1 && + left.Data2 == right.Data2 && + left.Data3 == right.Data3 && + left.Data4[0] == right.Data4[0] && + left.Data4[1] == right.Data4[1] && + left.Data4[2] == right.Data4[2] && + left.Data4[3] == right.Data4[3] && + left.Data4[4] == right.Data4[4] && + left.Data4[5] == right.Data4[5] && + left.Data4[6] == right.Data4[6] && + left.Data4[7] == right.Data4[7]; + } +} + +// Verify the specialization is marked precomputed and its value matches the +// SHA-1 computation (generate_guid + signature::data), which is the +// algorithm the primary template would use. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4307) // integral constant overflow from SHA-1 +#endif + +#define REQUIRE_PRECOMPUTED(...) \ + STATIC_REQUIRE(pinterface_guid<__VA_ARGS__>::precomputed); \ + STATIC_REQUIRE(equal(pinterface_guid<__VA_ARGS__>::value, generate_guid(signature<__VA_ARGS__>::data))) + +TEST_CASE("pinterface_guid_precomputed_ireference") +{ + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); + REQUIRE_PRECOMPUTED(IReference); +} + +TEST_CASE("pinterface_guid_precomputed_ireferencearray") +{ + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); + REQUIRE_PRECOMPUTED(IReferenceArray); +} + +TEST_CASE("pinterface_guid_precomputed_from_metadata") +{ + // These specializations are discovered from metadata: closed generic types + // that appear as method parameters, return types, or implemented interfaces + // in the Windows SDK. The IPropertyValue family uses IMap/IIterable/IKeyValuePair + // with and . + + // IMap / IMapView chains (used by PropertySet, ValueSet, etc.) + REQUIRE_PRECOMPUTED(IMap); + REQUIRE_PRECOMPUTED(IMap); + REQUIRE_PRECOMPUTED(IMapView); + REQUIRE_PRECOMPUTED(IMapView); + REQUIRE_PRECOMPUTED(IKeyValuePair); + REQUIRE_PRECOMPUTED(IKeyValuePair); + + // IIterable / IIterator over key-value pairs + REQUIRE_PRECOMPUTED(IIterable>); + REQUIRE_PRECOMPUTED(IIterable>); + REQUIRE_PRECOMPUTED(IIterator>); + REQUIRE_PRECOMPUTED(IIterator>); + + // IObservableMap and change handlers + REQUIRE_PRECOMPUTED(IObservableMap); + REQUIRE_PRECOMPUTED(IObservableMap); + REQUIRE_PRECOMPUTED(IMapChangedEventArgs); + REQUIRE_PRECOMPUTED(MapChangedEventHandler); + REQUIRE_PRECOMPUTED(MapChangedEventHandler); + + // TypedEventHandler from Windows.Foundation (e.g. IMemoryBufferReference.Closed) + REQUIRE_PRECOMPUTED(TypedEventHandler); + + // WwwFormUrlDecoder collections + REQUIRE_PRECOMPUTED(IIterable); + REQUIRE_PRECOMPUTED(IIterator); + REQUIRE_PRECOMPUTED(IVectorView); +} + +#undef REQUIRE_PRECOMPUTED + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/test/test/test.vcxproj b/test/test/test.vcxproj index 43928dab2..b28d3eddf 100644 --- a/test/test/test.vcxproj +++ b/test/test/test.vcxproj @@ -296,6 +296,7 @@ NotUsing NotUsing + diff --git a/test/test_cpp20_module/pinterface_guid_precomputed.cpp b/test/test_cpp20_module/pinterface_guid_precomputed.cpp new file mode 100644 index 000000000..4ff9117d7 --- /dev/null +++ b/test/test_cpp20_module/pinterface_guid_precomputed.cpp @@ -0,0 +1,119 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; +import winrt.Windows.Foundation.Collections; + +// Validate that pre-computed pinterface_guid specializations: +// 1. Have the precomputed flag set to true +// 2. Produce correct GUID values across module boundaries +// +// Tests cover both hand-written specializations (IReference/IReferenceArray +// in base_reference_produce.h) and code-generated specializations discovered +// from Windows SDK metadata (IMap, IIterable, TypedEventHandler, etc.). + +using namespace winrt; +using namespace winrt::impl; +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Collections; + +namespace +{ + constexpr bool equal(guid const& left, guid const& right) noexcept + { + return left.Data1 == right.Data1 && + left.Data2 == right.Data2 && + left.Data3 == right.Data3 && + left.Data4[0] == right.Data4[0] && + left.Data4[1] == right.Data4[1] && + left.Data4[2] == right.Data4[2] && + left.Data4[3] == right.Data4[3] && + left.Data4[4] == right.Data4[4] && + left.Data4[5] == right.Data4[5] && + left.Data4[6] == right.Data4[6] && + left.Data4[7] == right.Data4[7]; + } +} + +#define REQUIRE_PRECOMPUTED_GUID(expected_guid, ...) \ + STATIC_REQUIRE(pinterface_guid<__VA_ARGS__>::precomputed); \ + STATIC_REQUIRE(equal(guid(expected_guid), guid_of<__VA_ARGS__>())) + +TEST_CASE("module_pinterface_guid_ireference") +{ + REQUIRE_PRECOMPUTED_GUID("E5198CC8-2873-55F5-B0A1-84FF9E4AAD62", IReference); + REQUIRE_PRECOMPUTED_GUID("6EC9E41B-6709-5647-9918-A1270110FC4E", IReference); + REQUIRE_PRECOMPUTED_GUID("5AB7D2C3-6B62-5E71-A4B6-2D49C4F238FD", IReference); + REQUIRE_PRECOMPUTED_GUID("548CEFBD-BC8A-5FA0-8DF2-957440FC8BF4", IReference); + REQUIRE_PRECOMPUTED_GUID("513EF3AF-E784-5325-A91E-97C2B8111CF3", IReference); + REQUIRE_PRECOMPUTED_GUID("4DDA9E24-E69F-5C6A-A0A6-93427365AF2A", IReference); + REQUIRE_PRECOMPUTED_GUID("6755E376-53BB-568B-A11D-17239868309E", IReference); + REQUIRE_PRECOMPUTED_GUID("719CC2BA-3E76-5DEF-9F1A-38D85A145EA8", IReference); + REQUIRE_PRECOMPUTED_GUID("2F2D6C29-5473-5F3E-92E7-96572BB990E2", IReference); + REQUIRE_PRECOMPUTED_GUID("FB393EF3-BBAC-5BD5-9144-84F23576F415", IReference); + REQUIRE_PRECOMPUTED_GUID("3C00FD60-2950-5939-A21A-2D12C5A01B8A", IReference); + REQUIRE_PRECOMPUTED_GUID("FD416DFB-2A07-52EB-AAE3-DFCE14116C05", IReference); + REQUIRE_PRECOMPUTED_GUID("7D50F649-632C-51F9-849A-EE49428933EA", IReference); + REQUIRE_PRECOMPUTED_GUID("5541D8A7-497C-5AA4-86FC-7713ADBF2A2C", IReference); + REQUIRE_PRECOMPUTED_GUID("604D0C4C-91DE-5C2A-935F-362F13EAF800", IReference); + REQUIRE_PRECOMPUTED_GUID("84F14C22-A00A-5272-8D3D-82112E66DF00", IReference); + REQUIRE_PRECOMPUTED_GUID("61723086-8E53-5276-9F36-2A4BB93E2B75", IReference); + REQUIRE_PRECOMPUTED_GUID("80423F11-054F-5EAC-AFD3-63B6CE15E77B", IReference); +} + +TEST_CASE("module_pinterface_guid_ireferencearray") +{ + REQUIRE_PRECOMPUTED_GUID("2AF22683-3734-56D0-A60E-688CC85D1619", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("912F8FD7-ADC0-5D60-A896-7ED76089CC5B", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("6624A2DD-83F7-519C-9D55-BB1F6560456B", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("A6D080A5-B087-5BC2-9A9F-5CD687B4D1F7", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("97374B68-EB87-56CC-B18E-27EF0F9CFC0C", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("6E333271-2E2A-5955-8790-836C76EE53B6", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("38B60434-D67C-523E-9D0E-24D643411073", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("6AB1EA83-CB41-5F99-92CC-23BD4336A1FB", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("D301F253-E0A3-5D2B-9A41-A4D62BEC4623", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("A4095AAB-EB7D-5782-8FAD-1609DEA249AD", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("E8E72666-48CC-593F-BA85-2663496956E3", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("0385688E-E3C7-5C5E-A389-5524EDE349F1", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("9CD7A84F-0C80-59C5-B44E-977841BB43D9", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("EECF9838-C1C2-5B4A-976F-CEC261AE1D55", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("1B8E9594-588E-5A07-9E65-0731A4C9A2DB", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("AD73197D-2CFA-57A6-8993-9FAC40FEB791", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("39313214-5C7D-599D-AE5A-17D9D6492258", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("3B40E9D4-E0C3-56F6-B88B-E505EB73757B", IReferenceArray); + REQUIRE_PRECOMPUTED_GUID("8A444256-D661-5E9A-A72B-D8F1D7962D0C", IReferenceArray); +} + +TEST_CASE("module_pinterface_guid_from_metadata") +{ + // IMap / IMapView chains (used by PropertySet, ValueSet, etc.) + REQUIRE_PRECOMPUTED_GUID("1B0D3570-0877-5EC2-8A2C-3B9539506ACA", IMap); + REQUIRE_PRECOMPUTED_GUID("F6D1F700-49C2-52AE-8154-826F9908773C", IMap); + REQUIRE_PRECOMPUTED_GUID("BB78502A-F79D-54FA-92C9-90C5039FDF7E", IMapView); + REQUIRE_PRECOMPUTED_GUID("AC7F26F2-FEB7-5B2A-8AC4-345BC62CAEDE", IMapView); + REQUIRE_PRECOMPUTED_GUID("09335560-6C6B-5A26-9348-97B781132B20", IKeyValuePair); + REQUIRE_PRECOMPUTED_GUID("60310303-49C5-52E6-ABC6-A9B36ECCC716", IKeyValuePair); + + // IIterable / IIterator over key-value pairs + REQUIRE_PRECOMPUTED_GUID("FE2F3D47-5D47-5499-8374-430C7CDA0204", IIterable>); + REQUIRE_PRECOMPUTED_GUID("E9BDAAF0-CBF6-5C72-BE90-29CBF3A1319B", IIterable>); + REQUIRE_PRECOMPUTED_GUID("5DB5FA32-707C-5849-A06B-91C8EB9D10E8", IIterator>); + REQUIRE_PRECOMPUTED_GUID("05EB86F1-7140-5517-B88D-CBAEBE57E6B1", IIterator>); + + // IObservableMap and change handlers + REQUIRE_PRECOMPUTED_GUID("236AAC9D-FB12-5C4D-A41C-9E445FB4D7EC", IObservableMap); + REQUIRE_PRECOMPUTED_GUID("1E036276-2F60-55F6-B7F3-F86079E6900B", IObservableMap); + REQUIRE_PRECOMPUTED_GUID("60141EFB-F2F9-5377-96FD-F8C60D9558B5", IMapChangedEventArgs); + REQUIRE_PRECOMPUTED_GUID("24F981E5-DDCA-538D-AADA-A59906084CF1", MapChangedEventHandler); + REQUIRE_PRECOMPUTED_GUID("E2663F37-2E1B-500C-AD68-C3ED7A8F74C8", MapChangedEventHandler); + + // TypedEventHandler from Windows.Foundation (e.g. IMemoryBufferReference.Closed) + REQUIRE_PRECOMPUTED_GUID("F4637D4A-0760-5431-BFC0-24EB1D4F6C4F", TypedEventHandler); + + // WwwFormUrlDecoder collections + REQUIRE_PRECOMPUTED_GUID("876BE83B-7218-5BFB-A169-83152EF7E146", IIterable); + REQUIRE_PRECOMPUTED_GUID("32E54295-373C-50CB-80A1-468A990CA780", IIterator); + REQUIRE_PRECOMPUTED_GUID("B1F00D3B-1F06-5117-93EA-2A0D79116701", IVectorView); +} + +#undef REQUIRE_PRECOMPUTED_GUID diff --git a/test/test_cpp20_module/test_cpp20_module.vcxproj b/test/test_cpp20_module/test_cpp20_module.vcxproj index 1e76c487b..cf29456cc 100644 --- a/test/test_cpp20_module/test_cpp20_module.vcxproj +++ b/test/test_cpp20_module/test_cpp20_module.vcxproj @@ -107,6 +107,7 @@ + \ No newline at end of file From 512a6d41271c3b0bc8bc06d27f6465eeabe1358b Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 28 May 2026 13:54:26 -0700 Subject: [PATCH 08/17] Wrap namespace and ifndef --- cppwinrt/code_writers.h | 66 +++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index d1794cf96..e08c02227 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -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 @@ -562,40 +579,31 @@ namespace cppwinrt // 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). - w.write(R"( -extern "C++" -{ -namespace winrt::impl -{ -)"); + auto wrap_ns = wrap_extern_cpp_impl_namespace(w); for (auto&& [winrt_name, info] : instantiations) { auto guard = make_pinterface_guard(info.cpp_name); - auto& g = info.guid; - w.write("#ifndef %\n", guard); - w.write("#define %\n", guard); - w.write(" template <> struct pinterface_guid<%>\n", info.cpp_name); - w.write(" {\n"); - w.write(" static constexpr bool precomputed = true;\n"); - w.write(" static constexpr guid value{ "); - 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"); - w.write("#endif // %\n", guard); + { + auto wrap_guard = wrap_ifndef(w, guard); + w.write("#define %\n", guard); + w.write(" template <> struct pinterface_guid<%>\n", info.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"); + } } - - w.write(R"( -} // winrt::impl -} // extern "C++" -)"); } static void write_struct_category(writer& w, TypeDef const& type) From e94050f79ba5f702ad362c3f30432ea6238b114f Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 28 May 2026 14:12:21 -0700 Subject: [PATCH 09/17] Move manual IReference specializations from base_reference_produce into the common generation logic. --- cppwinrt/file_writers.h | 10 ++ cppwinrt/helpers.h | 88 ++++++++++++++ strings/base_reference_produce.h | 203 ------------------------------- 3 files changed, 98 insertions(+), 203 deletions(-) diff --git a/cppwinrt/file_writers.h b/cppwinrt/file_writers.h index bd37d8a92..968523eba 100644 --- a/cppwinrt/file_writers.h +++ b/cppwinrt/file_writers.h @@ -129,6 +129,16 @@ namespace cppwinrt { std::map instantiations; collect_generic_instantiations(w, members, instantiations); + + // For Windows.Foundation, also inject well-known IReference/IReferenceArray + // 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(instantiations); + } + write_generic_inst_specializations(w, instantiations); } diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index 4bc3f5b74..a1be4cbce 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1424,4 +1424,92 @@ namespace cppwinrt } } } + + // Add well-known IReference and IReferenceArray instantiations for standard primitive + // and Windows.Foundation struct types. These are emitted into Windows.Foundation.0.h so that + // consumers who only include Windows.Foundation.h (e.g. for boxing) still get precomputed GUIDs + // without requiring a header from a namespace that happens to use IReference etc. + // + // The pinterface signature format is: pinterface({open-type-guid};{arg-signature}) + // These signatures are part of the WinRT ABI specification and are immutable. + static void add_well_known_ireference_instantiations( + std::map& instantiations) + { + // IReference: {61c17706-2d65-11e0-9ae8-d48564015472} + // IReferenceArray: {61c17707-2d65-11e0-9ae8-d48564015472} + constexpr auto iref_guid = "{61c17706-2d65-11e0-9ae8-d48564015472}"; + constexpr auto iref_arr_guid = "{61c17707-2d65-11e0-9ae8-d48564015472}"; + + struct well_known_type + { + const char* winrt_name; // dedup key (WinRT display name) + const char* cpp_name; // C++ qualified name for the specialization + const char* arg_sig; // WinRT signature of the type argument + }; + + // DateTime = struct(Windows.Foundation.DateTime;i8) + // TimeSpan = struct(Windows.Foundation.TimeSpan;i8) + // Point = struct(Windows.Foundation.Point;f4;f4) + // Size = struct(Windows.Foundation.Size;f4;f4) + // Rect = struct(Windows.Foundation.Rect;f4;f4;f4;f4) + static constexpr well_known_type types[] = { + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "u1" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "i2" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "u2" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "i4" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "u4" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "i8" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "u8" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "f4" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "f8" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "c2" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "b1" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "string" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "g16" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.DateTime;i8)" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.TimeSpan;i8)" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.Point;f4;f4)" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.Size;f4;f4)" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.Rect;f4;f4;f4;f4)" }, + }; + + static constexpr well_known_type array_types[] = { + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "u1" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "i2" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "u2" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "i4" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "u4" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "i8" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "u8" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "f4" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "f8" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "c2" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "b1" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "string" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "cinterface(IInspectable)" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "g16" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.DateTime;i8)" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.TimeSpan;i8)" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.Point;f4;f4)" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.Size;f4;f4)" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.Rect;f4;f4;f4;f4)" }, + }; + + auto add_entries = [&](auto const& entries, const char* pinterface_guid) + { + for (auto& t : entries) + { + auto sig = std::string("pinterface(") + pinterface_guid + ";" + t.arg_sig + ")"; + auto [it, inserted] = instantiations.try_emplace(t.winrt_name); + if (inserted) + { + it->second.cpp_name = t.cpp_name; + it->second.guid = compute_guid_from_signature(sig); + } + } + }; + + add_entries(types, iref_guid); + add_entries(array_types, iref_arr_guid); + } } diff --git a/strings/base_reference_produce.h b/strings/base_reference_produce.h index d2c70521c..abffb3384 100644 --- a/strings/base_reference_produce.h +++ b/strings/base_reference_produce.h @@ -393,209 +393,6 @@ WINRT_EXPORT namespace winrt::impl static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateRectArray(value); } using itf = Windows::Foundation::IReferenceArray; }; - - // Pre-computed pinterface_guid specializations for standard IReference and IReferenceArray types. - // These avoid costly constexpr SHA1 computation at compile time. - // Wrapped in extern "C++" so that identical specializations across modules merge. - // #ifndef guards match those emitted by the code generator, preventing redefinition - // when both base_reference_produce.h and a generated .0.h define the same specialization. -} // winrt::impl - -extern "C++" -{ -namespace winrt::impl -{ -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint8_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint8_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xE5198CC8,0x2873,0x55F5,{ 0xB0,0xA1,0x84,0xFF,0x9E,0x4A,0xAD,0x62 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int16_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int16_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x6EC9E41B,0x6709,0x5647,{ 0x99,0x18,0xA1,0x27,0x01,0x10,0xFC,0x4E } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint16_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint16_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x5AB7D2C3,0x6B62,0x5E71,{ 0xA4,0xB6,0x2D,0x49,0xC4,0xF2,0x38,0xFD } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int32_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int32_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x548CEFBD,0xBC8A,0x5FA0,{ 0x8D,0xF2,0x95,0x74,0x40,0xFC,0x8B,0xF4 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint32_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint32_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x513EF3AF,0xE784,0x5325,{ 0xA9,0x1E,0x97,0xC2,0xB8,0x11,0x1C,0xF3 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int64_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__int64_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x4DDA9E24,0xE69F,0x5C6A,{ 0xA0,0xA6,0x93,0x42,0x73,0x65,0xAF,0x2A } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint64_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_std__uint64_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x6755E376,0x53BB,0x568B,{ 0xA1,0x1D,0x17,0x23,0x98,0x68,0x30,0x9E } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_float_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_float_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x719CC2BA,0x3E76,0x5DEF,{ 0x9F,0x1A,0x38,0xD8,0x5A,0x14,0x5E,0xA8 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_double_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_double_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x2F2D6C29,0x5473,0x5F3E,{ 0x92,0xE7,0x96,0x57,0x2B,0xB9,0x90,0xE2 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_char16_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_char16_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xFB393EF3,0xBBAC,0x5BD5,{ 0x91,0x44,0x84,0xF2,0x35,0x76,0xF4,0x15 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_bool_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_bool_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x3C00FD60,0x2950,0x5939,{ 0xA2,0x1A,0x2D,0x12,0xC5,0xA0,0x1B,0x8A } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__hstring_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__hstring_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xFD416DFB,0x2A07,0x52EB,{ 0xAA,0xE3,0xDF,0xCE,0x14,0x11,0x6C,0x05 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__guid_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__guid_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x7D50F649,0x632C,0x51F9,{ 0x84,0x9A,0xEE,0x49,0x42,0x89,0x33,0xEA } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__DateTime_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__DateTime_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x5541D8A7,0x497C,0x5AA4,{ 0x86,0xFC,0x77,0x13,0xAD,0xBF,0x2A,0x2C } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__TimeSpan_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__TimeSpan_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x604D0C4C,0x91DE,0x5C2A,{ 0x93,0x5F,0x36,0x2F,0x13,0xEA,0xF8,0x00 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Point_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Point_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x84F14C22,0xA00A,0x5272,{ 0x8D,0x3D,0x82,0x11,0x2E,0x66,0xDF,0x00 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Size_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Size_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x61723086,0x8E53,0x5276,{ 0x9F,0x36,0x2A,0x4B,0xB9,0x3E,0x2B,0x75 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Rect_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReference_winrt__Windows__Foundation__Rect_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x80423F11,0x054F,0x5EAC,{ 0xAF,0xD3,0x63,0xB6,0xCE,0x15,0xE7,0x7B } }; }; -#endif - -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint8_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint8_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x2AF22683,0x3734,0x56D0,{ 0xA6,0x0E,0x68,0x8C,0xC8,0x5D,0x16,0x19 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int16_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int16_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x912F8FD7,0xADC0,0x5D60,{ 0xA8,0x96,0x7E,0xD7,0x60,0x89,0xCC,0x5B } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint16_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint16_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x6624A2DD,0x83F7,0x519C,{ 0x9D,0x55,0xBB,0x1F,0x65,0x60,0x45,0x6B } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int32_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int32_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xA6D080A5,0xB087,0x5BC2,{ 0x9A,0x9F,0x5C,0xD6,0x87,0xB4,0xD1,0xF7 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint32_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint32_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x97374B68,0xEB87,0x56CC,{ 0xB1,0x8E,0x27,0xEF,0x0F,0x9C,0xFC,0x0C } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int64_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__int64_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x6E333271,0x2E2A,0x5955,{ 0x87,0x90,0x83,0x6C,0x76,0xEE,0x53,0xB6 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint64_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_std__uint64_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x38B60434,0xD67C,0x523E,{ 0x9D,0x0E,0x24,0xD6,0x43,0x41,0x10,0x73 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_float_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_float_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x6AB1EA83,0xCB41,0x5F99,{ 0x92,0xCC,0x23,0xBD,0x43,0x36,0xA1,0xFB } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_double_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_double_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xD301F253,0xE0A3,0x5D2B,{ 0x9A,0x41,0xA4,0xD6,0x2B,0xEC,0x46,0x23 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_char16_t_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_char16_t_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xA4095AAB,0xEB7D,0x5782,{ 0x8F,0xAD,0x16,0x09,0xDE,0xA2,0x49,0xAD } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_bool_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_bool_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xE8E72666,0x48CC,0x593F,{ 0xBA,0x85,0x26,0x63,0x49,0x69,0x56,0xE3 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__hstring_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__hstring_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x0385688E,0xE3C7,0x5C5E,{ 0xA3,0x89,0x55,0x24,0xED,0xE3,0x49,0xF1 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__IInspectable_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__IInspectable_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x9CD7A84F,0x0C80,0x59C5,{ 0xB4,0x4E,0x97,0x78,0x41,0xBB,0x43,0xD9 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__guid_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__guid_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xEECF9838,0xC1C2,0x5B4A,{ 0x97,0x6F,0xCE,0xC2,0x61,0xAE,0x1D,0x55 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__DateTime_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__DateTime_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x1B8E9594,0x588E,0x5A07,{ 0x9E,0x65,0x07,0x31,0xA4,0xC9,0xA2,0xDB } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__TimeSpan_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__TimeSpan_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0xAD73197D,0x2CFA,0x57A6,{ 0x89,0x93,0x9F,0xAC,0x40,0xFE,0xB7,0x91 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Point_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Point_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x39313214,0x5C7D,0x599D,{ 0xAE,0x5A,0x17,0xD9,0xD6,0x49,0x22,0x58 } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Size_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Size_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x3B40E9D4,0xE0C3,0x56F6,{ 0xB8,0x8B,0xE5,0x05,0xEB,0x73,0x75,0x7B } }; }; -#endif -#ifndef WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Rect_ -#define WINRT_IMPL_PINTERFACE_GUID_winrt__Windows__Foundation__IReferenceArray_winrt__Windows__Foundation__Rect_ - template <> struct pinterface_guid> - { static constexpr bool precomputed = true; static constexpr guid value{ 0x8A444256,0xD661,0x5E9A,{ 0xA7,0x2B,0xD8,0xF1,0xD7,0x96,0x2D,0x0C } }; }; -#endif -} // winrt::impl -} // extern "C++" - -namespace winrt::impl -{ } WINRT_EXPORT namespace winrt::Windows::Foundation From 5e58472774e73c1b50f3e29f090817f86332d180 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 28 May 2026 14:25:02 -0700 Subject: [PATCH 10/17] Typo in IReference --- cppwinrt/helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index a1be4cbce..71802c595 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1465,7 +1465,7 @@ namespace cppwinrt { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "c2" }, { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "b1" }, { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "string" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "g16" }, + { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "g16" }, { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.DateTime;i8)" }, { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.TimeSpan;i8)" }, { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.Point;f4;f4)" }, @@ -1487,7 +1487,7 @@ namespace cppwinrt { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "b1" }, { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "string" }, { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "cinterface(IInspectable)" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "g16" }, + { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "g16" }, { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.DateTime;i8)" }, { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.TimeSpan;i8)" }, { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.Point;f4;f4)" }, From 81d2d022cdc659e6651b2b66c7975a3c110ae187 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 28 May 2026 18:56:56 -0700 Subject: [PATCH 11/17] Apply CoPilot suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- test/test/pinterface_guid_precomputed.cpp | 8 +++++--- test/test_cpp20_module/pinterface_guid_precomputed.cpp | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/test/pinterface_guid_precomputed.cpp b/test/test/pinterface_guid_precomputed.cpp index e41d2a02c..8ec754b4a 100644 --- a/test/test/pinterface_guid_precomputed.cpp +++ b/test/test/pinterface_guid_precomputed.cpp @@ -4,9 +4,11 @@ // 1. Have the precomputed flag set to true // 2. Produce GUID values matching the algorithmic SHA-1 computation // -// Tests cover both hand-written specializations (IReference/IReferenceArray -// in base_reference_produce.h) and code-generated specializations discovered -// from Windows SDK metadata (IMap, IIterable, TypedEventHandler, etc.). +// Tests cover both code-generated IReference/IReferenceArray +// specializations injected via add_well_known_ireference_instantiations into +// the generated Windows.Foundation.0.h output and other code-generated +// specializations discovered from Windows SDK metadata (IMap, IIterable, +// TypedEventHandler, etc.). using namespace winrt; using namespace winrt::impl; diff --git a/test/test_cpp20_module/pinterface_guid_precomputed.cpp b/test/test_cpp20_module/pinterface_guid_precomputed.cpp index 4ff9117d7..02ca02c90 100644 --- a/test/test_cpp20_module/pinterface_guid_precomputed.cpp +++ b/test/test_cpp20_module/pinterface_guid_precomputed.cpp @@ -8,8 +8,9 @@ import winrt.Windows.Foundation.Collections; // 1. Have the precomputed flag set to true // 2. Produce correct GUID values across module boundaries // -// Tests cover both hand-written specializations (IReference/IReferenceArray -// in base_reference_produce.h) and code-generated specializations discovered +// Tests cover both well-known IReference/IReferenceArray specializations +// injected by add_well_known_ireference_instantiations into the generated +// Windows.Foundation.0.h output and code-generated specializations discovered // from Windows SDK metadata (IMap, IIterable, TypedEventHandler, etc.). using namespace winrt; From f8a90028122d04650734fbc53eb57ee195f5e54b Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 28 May 2026 21:20:10 -0700 Subject: [PATCH 12/17] Synthesize GenericTypeInstSig for IReference specializations, instead of hard-coding signature data --- cppwinrt/cppwinrt.vcxproj | 4 +- cppwinrt/file_writers.h | 2 +- cppwinrt/helpers.h | 181 ++++++++++++++++++++++++-------------- cppwinrt/packages.config | 2 +- 4 files changed, 117 insertions(+), 72 deletions(-) diff --git a/cppwinrt/cppwinrt.vcxproj b/cppwinrt/cppwinrt.vcxproj index b8beed890..e190b8499 100644 --- a/cppwinrt/cppwinrt.vcxproj +++ b/cppwinrt/cppwinrt.vcxproj @@ -1,6 +1,6 @@ - + Debug @@ -309,6 +309,6 @@ 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}. - + \ No newline at end of file diff --git a/cppwinrt/file_writers.h b/cppwinrt/file_writers.h index 968523eba..0f42bde46 100644 --- a/cppwinrt/file_writers.h +++ b/cppwinrt/file_writers.h @@ -136,7 +136,7 @@ namespace cppwinrt // boxing types, without depending on other namespace headers. if (ns == "Windows.Foundation") { - add_well_known_ireference_instantiations(instantiations); + add_well_known_ireference_instantiations(w, members, instantiations); } write_generic_inst_specializations(w, instantiations); diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index 71802c595..1da256f00 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1430,86 +1430,131 @@ namespace cppwinrt // consumers who only include Windows.Foundation.h (e.g. for boxing) still get precomputed GUIDs // without requiring a header from a namespace that happens to use IReference etc. // - // The pinterface signature format is: pinterface({open-type-guid};{arg-signature}) - // These signatures are part of the WinRT ABI specification and are immutable. + // Uses the same code path as metadata-discovered instantiations by constructing + // GenericTypeInstSig objects and feeding them through collect_generic_inst_recursive. + // This ensures cpp_name, guard names, and signatures are always consistent. static void add_well_known_ireference_instantiations( + writer& w, + cache::namespace_members const& members, std::map& instantiations) { - // IReference: {61c17706-2d65-11e0-9ae8-d48564015472} - // IReferenceArray: {61c17707-2d65-11e0-9ae8-d48564015472} - constexpr auto iref_guid = "{61c17706-2d65-11e0-9ae8-d48564015472}"; - constexpr auto iref_arr_guid = "{61c17707-2d65-11e0-9ae8-d48564015472}"; - - struct well_known_type + auto find_type = [&](std::string_view name) -> TypeDef { - const char* winrt_name; // dedup key (WinRT display name) - const char* cpp_name; // C++ qualified name for the specialization - const char* arg_sig; // WinRT signature of the type argument - }; - - // DateTime = struct(Windows.Foundation.DateTime;i8) - // TimeSpan = struct(Windows.Foundation.TimeSpan;i8) - // Point = struct(Windows.Foundation.Point;f4;f4) - // Size = struct(Windows.Foundation.Size;f4;f4) - // Rect = struct(Windows.Foundation.Rect;f4;f4;f4;f4) - static constexpr well_known_type types[] = { - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "u1" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "i2" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "u2" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "i4" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "u4" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "i8" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "u8" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "f4" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "f8" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "c2" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "b1" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "string" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "g16" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.DateTime;i8)" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.TimeSpan;i8)" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.Point;f4;f4)" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.Size;f4;f4)" }, - { "Windows.Foundation.IReference`1", "winrt::Windows::Foundation::IReference", "struct(Windows.Foundation.Rect;f4;f4;f4;f4)" }, + auto it = members.types.find(name); + return it != members.types.end() ? it->second : TypeDef{}; }; - static constexpr well_known_type array_types[] = { - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "u1" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "i2" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "u2" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "i4" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "u4" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "i8" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "u8" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "f4" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "f8" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "c2" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "b1" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "string" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "cinterface(IInspectable)" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "g16" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.DateTime;i8)" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.TimeSpan;i8)" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.Point;f4;f4)" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.Size;f4;f4)" }, - { "Windows.Foundation.IReferenceArray`1", "winrt::Windows::Foundation::IReferenceArray", "struct(Windows.Foundation.Rect;f4;f4;f4;f4)" }, - }; + auto iref = find_type("IReference`1"); + auto iref_arr = find_type("IReferenceArray`1"); + if (!iref || !iref_arr) return; - auto add_entries = [&](auto const& entries, const char* pinterface_guid) + // Find the System.Guid TypeRef via IPropertyValue.GetGuid's return type. + // There is no TypeDef for System.Guid, only scattered TypeRefs. + // IPropertyValue is in Windows.Foundation, so it's available in members. + // The GetGuid method is at a stable ABI vtable position (index 14, 0-based + // within MethodList), but we fall back to a name search if that doesn't match. + coded_index guid_type_ref{}; + auto ipv = find_type("IPropertyValue"); + if (ipv) { - for (auto& t : entries) + // Find the GetGuid method — try index 14 first (stable ABI vtable position), + // then fall back to linear search. + auto methods = ipv.MethodList(); + MethodDef get_guid_method{}; + + if (size(methods) > 14 && methods.first[14].Name() == "GetGuid") + { + get_guid_method = methods.first[14]; + } + else { - auto sig = std::string("pinterface(") + pinterface_guid + ";" + t.arg_sig + ")"; - auto [it, inserted] = instantiations.try_emplace(t.winrt_name); - if (inserted) + for (auto&& m : methods) { - it->second.cpp_name = t.cpp_name; - it->second.guid = compute_guid_from_signature(sig); + if (m.Name() == "GetGuid") + { + get_guid_method = m; + break; + } } } - }; - add_entries(types, iref_guid); - add_entries(array_types, iref_arr_guid); + if (get_guid_method) + { + auto method_sig = get_guid_method.Signature(); + auto const& ret_type = method_sig.ReturnType().Type().Type(); + if (std::holds_alternative>(ret_type)) + { + guid_type_ref = std::get>(ret_type); + } + } + } + + // Collect TypeSig args for all well-known type arguments. + // Primitives use ElementType directly; WinRT structs use their TypeDef; + // Guid uses the TypeRef found above; Object uses ElementType::Object. + std::vector type_args; + type_args.reserve(20); + + // Fundamental types + type_args.emplace_back(ElementType::U1); + type_args.emplace_back(ElementType::I2); + type_args.emplace_back(ElementType::U2); + type_args.emplace_back(ElementType::I4); + type_args.emplace_back(ElementType::U4); + type_args.emplace_back(ElementType::I8); + type_args.emplace_back(ElementType::U8); + type_args.emplace_back(ElementType::R4); + type_args.emplace_back(ElementType::R8); + type_args.emplace_back(ElementType::Char); + type_args.emplace_back(ElementType::Boolean); + type_args.emplace_back(ElementType::String); + + // Guid (only if we found the TypeRef) + if (guid_type_ref) + { + type_args.emplace_back(guid_type_ref); + } + + // Windows.Foundation struct types + static constexpr std::string_view struct_names[] = { "DateTime", "TimeSpan", "Point", "Size", "Rect" }; + for (auto name : struct_names) + { + auto td = find_type(name); + if (td) + { + type_args.emplace_back(td.coded_index()); + } + } + + auto iref_coded = iref.coded_index(); + auto iref_arr_coded = iref_arr.coded_index(); + + for (auto& arg_sig : type_args) + { + // IReference + { + std::vector args; + args.push_back(arg_sig); + GenericTypeInstSig inst{ iref_coded, std::move(args) }; + collect_generic_inst_recursive(w, inst, {}, instantiations); + } + // IReferenceArray + { + std::vector args; + args.push_back(arg_sig); + GenericTypeInstSig inst{ iref_arr_coded, std::move(args) }; + collect_generic_inst_recursive(w, inst, {}, instantiations); + } + } + + // IReferenceArray is valid (for passing arrays of inspectable objects), + // but IReference is not (IReference boxes value types; Object is a + // reference type). So Object is not in the shared type_args list above. + { + std::vector args; + args.push_back(TypeSig{ ElementType::Object }); + GenericTypeInstSig inst{ iref_arr_coded, std::move(args) }; + collect_generic_inst_recursive(w, inst, {}, instantiations); + } } } diff --git a/cppwinrt/packages.config b/cppwinrt/packages.config index 9b3264e46..e7b030d0e 100644 --- a/cppwinrt/packages.config +++ b/cppwinrt/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file From 758a0a1b22dba890d4b25e6409c19ae4ff349f5b Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 28 May 2026 22:06:59 -0700 Subject: [PATCH 13/17] Remove leftover name_v machinery --- cppwinrt/code_writers.h | 6 +-- cppwinrt/helpers.h | 100 ++++------------------------------------ 2 files changed, 12 insertions(+), 94 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index e08c02227..76d076f51 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -581,13 +581,13 @@ namespace winrt::impl // #ifndef guards prevent redefinition within a single TU (SCC-consolidated modules). auto wrap_ns = wrap_extern_cpp_impl_namespace(w); - for (auto&& [winrt_name, info] : instantiations) + for (auto&& [cpp_name, info] : instantiations) { - auto guard = make_pinterface_guard(info.cpp_name); + 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", info.cpp_name); + 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{ "); diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index 1da256f00..0a945c655 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1157,90 +1157,9 @@ namespace cppwinrt struct generic_inst_info { - std::string cpp_name; guid_value guid; }; - // ---- winrt_name_builder: builds WinRT display names from metadata ---- - struct winrt_name_builder - { - static std::string get_name(GenericTypeInstSig const& type, type_arg_stack const& resolve = {}) - { - auto generic_type = type.GenericType(); - auto [ns, name] = get_type_namespace_and_name(generic_type); - - std::string result = std::string(ns) + "." + std::string(name) + "<"; - bool first = true; - for (auto&& arg : type.GenericArgs()) - { - if (!first) result += ", "; - first = false; - result += get_arg_name(arg, resolve); - } - result += ">"; - return result; - } - - private: - static std::string get_element_name(ElementType t) - { - switch (t) - { - case ElementType::Boolean: return "Boolean"; - case ElementType::Char: return "Char16"; - case ElementType::I1: return "Int8"; - case ElementType::U1: return "UInt8"; - case ElementType::I2: return "Int16"; - case ElementType::U2: return "UInt16"; - case ElementType::I4: return "Int32"; - case ElementType::U4: return "UInt32"; - case ElementType::I8: return "Int64"; - case ElementType::U8: return "UInt64"; - case ElementType::R4: return "Single"; - case ElementType::R8: return "Double"; - case ElementType::String: return "String"; - case ElementType::Object: return "Object"; - default: return {}; - } - } - - static std::string get_typedef_name(TypeDef const& td) - { - return std::string(td.TypeNamespace()) + "." + std::string(td.TypeName()); - } - - static std::string get_arg_name(TypeSig const& sig, type_arg_stack const& resolve) - { - return call(sig.Type(), - [](ElementType t) -> std::string { return get_element_name(t); }, - [&](GenericTypeIndex idx) -> std::string - { - if (!resolve.empty() && idx.index < resolve.back().size()) - { - type_arg_stack parent_resolve(resolve.begin(), resolve.end() - 1); - return get_arg_name(resolve.back()[idx.index], parent_resolve); - } - return {}; - }, - [](GenericMethodTypeIndex) -> std::string { return {}; }, - [&](coded_index const& t) -> std::string - { - switch (t.type()) - { - case TypeDefOrRef::TypeDef: return get_typedef_name(t.TypeDef()); - case TypeDefOrRef::TypeRef: - { - auto tr = t.TypeRef(); - if (tr.TypeNamespace() == "System" && tr.TypeName() == "Guid") return "Guid"; - return get_typedef_name(find_required(tr)); - } - default: return get_name(t.TypeSpec().Signature().GenericTypeInst(), resolve); - } - }, - [&](GenericTypeInstSig const& t) -> std::string { return get_name(t, resolve); }); - } - }; - // ---- Recursive collection of concrete generic instantiations ---- // Walks InterfaceImpl chains and method signatures, carrying concrete TypeSig args to resolve GenericTypeIndex. @@ -1310,19 +1229,14 @@ namespace cppwinrt } } - // Build a resolution stack with our concrete args appended - type_arg_stack resolve = outer_resolve; - resolve.push_back(concrete_args); - - // Use winrt_name as the dedup key. Only do expensive work if this is a new entry. - auto winrt_name = winrt_name_builder::get_name(type, outer_resolve); - auto [it, inserted] = instantiations.try_emplace(std::move(winrt_name)); + // Use cpp_name as the dedup key. Only do expensive work if this is a new entry. + auto cpp_name = w.write_temp("%", type); + auto [it, inserted] = instantiations.try_emplace(std::move(cpp_name)); if (!inserted) { return; } - it->second.cpp_name = w.write_temp("%", type); it->second.guid = compute_guid_from_signature(signature_builder::get_signature(type, outer_resolve)); // Recurse into generic args that are themselves generic instantiations @@ -1341,12 +1255,16 @@ namespace cppwinrt } } - // Recurse into the generic type's required interfaces (e.g., IMap : IIterable, etc.) - auto base_type = find_required(type.GenericType()); + // Build a resolution stack with our concrete args appended + type_arg_stack resolve = outer_resolve; + resolve.push_back(concrete_args); // Push the writer's generic_param_stack so write_temp resolves GenericTypeIndex in nested calls auto writer_guard = w.push_generic_params(type); + // Recurse into the generic type's required interfaces (e.g., IMap : IIterable, etc.) + auto base_type = find_required(type.GenericType()); + for (auto&& impl : base_type.InterfaceImpl()) { auto iface = impl.Interface(); From 8ba0c2e3f2d49f7b9cb07250055c2d62d67a720f Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Fri, 29 May 2026 16:51:46 -0700 Subject: [PATCH 14/17] Update winmd nuget package to 1.0.260529.3 to fix build break --- cppwinrt/cppwinrt.vcxproj | 4 ++-- cppwinrt/packages.config | 2 +- natvis/cppwinrtvisualizer.vcxproj | 4 ++-- natvis/packages.config | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cppwinrt/cppwinrt.vcxproj b/cppwinrt/cppwinrt.vcxproj index e190b8499..3efa7a64c 100644 --- a/cppwinrt/cppwinrt.vcxproj +++ b/cppwinrt/cppwinrt.vcxproj @@ -1,6 +1,6 @@ - + Debug @@ -309,6 +309,6 @@ 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}. - + \ No newline at end of file diff --git a/cppwinrt/packages.config b/cppwinrt/packages.config index e7b030d0e..7b2ee1f28 100644 --- a/cppwinrt/packages.config +++ b/cppwinrt/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/natvis/cppwinrtvisualizer.vcxproj b/natvis/cppwinrtvisualizer.vcxproj index af3fbcf1f..4232a41ea 100644 --- a/natvis/cppwinrtvisualizer.vcxproj +++ b/natvis/cppwinrtvisualizer.vcxproj @@ -1,6 +1,6 @@ - + Debug @@ -321,6 +321,6 @@ - + \ No newline at end of file diff --git a/natvis/packages.config b/natvis/packages.config index 7907cba44..2176891c4 100644 --- a/natvis/packages.config +++ b/natvis/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file From 68d98abdfc6e924611d0c6cd123d00f378e061e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 30 May 2026 00:17:57 +0000 Subject: [PATCH 15/17] Fix i686 cross-build by avoiding removed winmd signature constructors --- cppwinrt/helpers.h | 179 +++++++++++++++++++++++---------------------- 1 file changed, 90 insertions(+), 89 deletions(-) diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index 0a945c655..c88ccb9f7 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1348,9 +1348,8 @@ namespace cppwinrt // consumers who only include Windows.Foundation.h (e.g. for boxing) still get precomputed GUIDs // without requiring a header from a namespace that happens to use IReference etc. // - // Uses the same code path as metadata-discovered instantiations by constructing - // GenericTypeInstSig objects and feeding them through collect_generic_inst_recursive. - // This ensures cpp_name, guard names, and signatures are always consistent. + // Uses canonical metadata TypeSig values from IPropertyValue getters to produce + // stable cpp names and parameterized-interface GUIDs for these common projections. static void add_well_known_ireference_instantiations( writer& w, cache::namespace_members const& members, @@ -1366,113 +1365,115 @@ namespace cppwinrt auto iref_arr = find_type("IReferenceArray`1"); if (!iref || !iref_arr) return; - // Find the System.Guid TypeRef via IPropertyValue.GetGuid's return type. - // There is no TypeDef for System.Guid, only scattered TypeRefs. - // IPropertyValue is in Windows.Foundation, so it's available in members. - // The GetGuid method is at a stable ABI vtable position (index 14, 0-based - // within MethodList), but we fall back to a name search if that doesn't match. - coded_index guid_type_ref{}; auto ipv = find_type("IPropertyValue"); - if (ipv) + if (!ipv) { - // Find the GetGuid method — try index 14 first (stable ABI vtable position), - // then fall back to linear search. - auto methods = ipv.MethodList(); - MethodDef get_guid_method{}; + return; + } - if (size(methods) > 14 && methods.first[14].Name() == "GetGuid") - { - get_guid_method = methods.first[14]; - } - else + // Collect TypeSig args from IPropertyValue getter return types, which provide + // canonical metadata TypeSig representations for primitive and struct types. + std::vector type_args; + type_args.reserve(19); + + auto append_method_return_type = [&](std::string_view method_name) -> bool + { + for (auto&& method : ipv.MethodList()) { - for (auto&& m : methods) + if (method.Name() == method_name) { - if (m.Name() == "GetGuid") + auto sig = method.Signature(); + if (sig.ReturnType()) { - get_guid_method = m; - break; + type_args.push_back(sig.ReturnType().Type()); + return true; } + return false; } } - - if (get_guid_method) - { - auto method_sig = get_guid_method.Signature(); - auto const& ret_type = method_sig.ReturnType().Type().Type(); - if (std::holds_alternative>(ret_type)) - { - guid_type_ref = std::get>(ret_type); - } + return false; + }; + static constexpr std::string_view method_names[] = + { + "GetUInt8", "GetInt16", "GetUInt16", "GetInt32", "GetUInt32", "GetInt64", "GetUInt64", + "GetSingle", "GetDouble", "GetChar16", "GetBoolean", "GetString", + "GetGuid", "GetDateTime", "GetTimeSpan", "GetPoint", "GetSize", "GetRect", "GetInspectable" + }; + for (auto method_name : method_names) + { + append_method_return_type(method_name); + } + + auto element_signature = [](ElementType type) -> std::string + { + switch (type) + { + case ElementType::Boolean: return "b1"; + case ElementType::Char: return "c2"; + case ElementType::I1: return "i1"; + case ElementType::U1: return "u1"; + case ElementType::I2: return "i2"; + case ElementType::U2: return "u2"; + case ElementType::I4: return "i4"; + case ElementType::U4: return "u4"; + case ElementType::I8: return "i8"; + case ElementType::U8: return "u8"; + case ElementType::R4: return "f4"; + case ElementType::R8: return "f8"; + case ElementType::String: return "string"; + case ElementType::Object: return "cinterface(IInspectable)"; + default: return {}; } - } - - // Collect TypeSig args for all well-known type arguments. - // Primitives use ElementType directly; WinRT structs use their TypeDef; - // Guid uses the TypeRef found above; Object uses ElementType::Object. - std::vector type_args; - type_args.reserve(20); - - // Fundamental types - type_args.emplace_back(ElementType::U1); - type_args.emplace_back(ElementType::I2); - type_args.emplace_back(ElementType::U2); - type_args.emplace_back(ElementType::I4); - type_args.emplace_back(ElementType::U4); - type_args.emplace_back(ElementType::I8); - type_args.emplace_back(ElementType::U8); - type_args.emplace_back(ElementType::R4); - type_args.emplace_back(ElementType::R8); - type_args.emplace_back(ElementType::Char); - type_args.emplace_back(ElementType::Boolean); - type_args.emplace_back(ElementType::String); - - // Guid (only if we found the TypeRef) - if (guid_type_ref) - { - type_args.emplace_back(guid_type_ref); - } + }; - // Windows.Foundation struct types - static constexpr std::string_view struct_names[] = { "DateTime", "TimeSpan", "Point", "Size", "Rect" }; - for (auto name : struct_names) + auto get_type_signature = [&](TypeSig const& type) -> std::string { - auto td = find_type(name); - if (td) - { - type_args.emplace_back(td.coded_index()); - } - } + return call(type.Type(), + [&](ElementType t) -> std::string + { + return element_signature(t); + }, + [&](coded_index const& t) -> std::string + { + return signature_builder::get_signature(t); + }, + [](auto const&) -> std::string + { + return {}; + }); + }; - auto iref_coded = iref.coded_index(); - auto iref_arr_coded = iref_arr.coded_index(); + auto iref_guid = format_guid_signature(extract_guid(iref)); + auto iref_arr_guid = format_guid_signature(extract_guid(iref_arr)); - for (auto& arg_sig : type_args) + auto add_instantiation = [&](std::string_view template_name, std::string_view generic_guid, TypeSig const& arg) { - // IReference + auto arg_signature = get_type_signature(arg); + if (arg_signature.empty()) { - std::vector args; - args.push_back(arg_sig); - GenericTypeInstSig inst{ iref_coded, std::move(args) }; - collect_generic_inst_recursive(w, inst, {}, instantiations); + return; } - // IReferenceArray + + auto cpp_name = w.write_temp("winrt::Windows::Foundation::%<%>", template_name, arg); + auto sig = std::string("pinterface(") + std::string(generic_guid) + ";" + arg_signature + ")"; + auto [it, inserted] = instantiations.try_emplace(std::move(cpp_name)); + if (inserted) { - std::vector args; - args.push_back(arg_sig); - GenericTypeInstSig inst{ iref_arr_coded, std::move(args) }; - collect_generic_inst_recursive(w, inst, {}, instantiations); + it->second.guid = compute_guid_from_signature(sig); } - } + }; - // IReferenceArray is valid (for passing arrays of inspectable objects), - // but IReference is not (IReference boxes value types; Object is a - // reference type). So Object is not in the shared type_args list above. + for (auto const& arg_sig : type_args) { - std::vector args; - args.push_back(TypeSig{ ElementType::Object }); - GenericTypeInstSig inst{ iref_arr_coded, std::move(args) }; - collect_generic_inst_recursive(w, inst, {}, instantiations); + bool const is_object = + std::holds_alternative(arg_sig.Type()) && + std::get(arg_sig.Type()) == ElementType::Object; + + if (!is_object) + { + add_instantiation("IReference", iref_guid, arg_sig); + } + add_instantiation("IReferenceArray", iref_arr_guid, arg_sig); } } } From 9b1d5eef0c3a1d7a42983fd8f658b8eb53311913 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 30 May 2026 00:49:08 +0000 Subject: [PATCH 16/17] Apply remaining changes --- cppwinrt/helpers.h | 171 +++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 91 deletions(-) diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index c88ccb9f7..4455d5f22 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1348,8 +1348,9 @@ namespace cppwinrt // consumers who only include Windows.Foundation.h (e.g. for boxing) still get precomputed GUIDs // without requiring a header from a namespace that happens to use IReference etc. // - // Uses canonical metadata TypeSig values from IPropertyValue getters to produce - // stable cpp names and parameterized-interface GUIDs for these common projections. + // Uses the same code path as metadata-discovered instantiations by constructing + // GenericTypeInstSig objects and feeding them through collect_generic_inst_recursive. + // This ensures cpp_name, guard names, and signatures are always consistent. static void add_well_known_ireference_instantiations( writer& w, cache::namespace_members const& members, @@ -1365,115 +1366,103 @@ namespace cppwinrt auto iref_arr = find_type("IReferenceArray`1"); if (!iref || !iref_arr) return; + // Find the System.Guid TypeRef via IPropertyValue.GetGuid's return type. + // There is no TypeDef for System.Guid, only scattered TypeRefs. + // IPropertyValue is in Windows.Foundation, so it's available in members. + // The GetGuid method is at a stable ABI vtable position (index 14, 0-based + // within MethodList), but we fall back to a name search if that doesn't match. + coded_index guid_type_ref{}; auto ipv = find_type("IPropertyValue"); - if (!ipv) + if (ipv) { - return; - } + // Find the GetGuid method — try index 14 first (stable ABI vtable position), + // then fall back to linear search. + auto methods = ipv.MethodList(); + MethodDef get_guid_method{}; - // Collect TypeSig args from IPropertyValue getter return types, which provide - // canonical metadata TypeSig representations for primitive and struct types. - std::vector type_args; - type_args.reserve(19); - - auto append_method_return_type = [&](std::string_view method_name) -> bool - { - for (auto&& method : ipv.MethodList()) + if (size(methods) > 14 && methods.first[14].Name() == "GetGuid") { - if (method.Name() == method_name) + get_guid_method = methods.first[14]; + } + else + { + for (auto&& m : methods) { - auto sig = method.Signature(); - if (sig.ReturnType()) + if (m.Name() == "GetGuid") { - type_args.push_back(sig.ReturnType().Type()); - return true; + get_guid_method = m; + break; } - return false; } } - return false; - }; - static constexpr std::string_view method_names[] = - { - "GetUInt8", "GetInt16", "GetUInt16", "GetInt32", "GetUInt32", "GetInt64", "GetUInt64", - "GetSingle", "GetDouble", "GetChar16", "GetBoolean", "GetString", - "GetGuid", "GetDateTime", "GetTimeSpan", "GetPoint", "GetSize", "GetRect", "GetInspectable" - }; - for (auto method_name : method_names) - { - append_method_return_type(method_name); - } - - auto element_signature = [](ElementType type) -> std::string - { - switch (type) - { - case ElementType::Boolean: return "b1"; - case ElementType::Char: return "c2"; - case ElementType::I1: return "i1"; - case ElementType::U1: return "u1"; - case ElementType::I2: return "i2"; - case ElementType::U2: return "u2"; - case ElementType::I4: return "i4"; - case ElementType::U4: return "u4"; - case ElementType::I8: return "i8"; - case ElementType::U8: return "u8"; - case ElementType::R4: return "f4"; - case ElementType::R8: return "f8"; - case ElementType::String: return "string"; - case ElementType::Object: return "cinterface(IInspectable)"; - default: return {}; - } - }; - auto get_type_signature = [&](TypeSig const& type) -> std::string - { - return call(type.Type(), - [&](ElementType t) -> std::string - { - return element_signature(t); - }, - [&](coded_index const& t) -> std::string - { - return signature_builder::get_signature(t); - }, - [](auto const&) -> std::string + if (get_guid_method) + { + auto method_sig = get_guid_method.Signature(); + auto const& ret_type = method_sig.ReturnType().Type().Type(); + if (std::holds_alternative>(ret_type)) { - return {}; - }); - }; + guid_type_ref = std::get>(ret_type); + } + } + } - auto iref_guid = format_guid_signature(extract_guid(iref)); - auto iref_arr_guid = format_guid_signature(extract_guid(iref_arr)); + // Collect TypeSig args for all well-known type arguments. + // Primitives use ElementType directly; WinRT structs use their TypeDef; + // Guid uses the TypeRef found above; Object uses ElementType::Object. + std::vector type_args; + type_args.reserve(20); + + // Fundamental types + type_args.push_back(TypeSig{ ElementType::U1 }); + type_args.push_back(TypeSig{ ElementType::I2 }); + type_args.push_back(TypeSig{ ElementType::U2 }); + type_args.push_back(TypeSig{ ElementType::I4 }); + type_args.push_back(TypeSig{ ElementType::U4 }); + type_args.push_back(TypeSig{ ElementType::I8 }); + type_args.push_back(TypeSig{ ElementType::U8 }); + type_args.push_back(TypeSig{ ElementType::R4 }); + type_args.push_back(TypeSig{ ElementType::R8 }); + type_args.push_back(TypeSig{ ElementType::Char }); + type_args.push_back(TypeSig{ ElementType::Boolean }); + type_args.push_back(TypeSig{ ElementType::String }); + + // Guid (only if we found the TypeRef) + if (guid_type_ref) + { + type_args.push_back(TypeSig{ guid_type_ref }); + } - auto add_instantiation = [&](std::string_view template_name, std::string_view generic_guid, TypeSig const& arg) + // Windows.Foundation struct types + static constexpr std::string_view struct_names[] = { "DateTime", "TimeSpan", "Point", "Size", "Rect" }; + for (auto name : struct_names) { - auto arg_signature = get_type_signature(arg); - if (arg_signature.empty()) + auto td = find_type(name); + if (td) { - return; + type_args.push_back(TypeSig{ td.coded_index() }); } + } - auto cpp_name = w.write_temp("winrt::Windows::Foundation::%<%>", template_name, arg); - auto sig = std::string("pinterface(") + std::string(generic_guid) + ";" + arg_signature + ")"; - auto [it, inserted] = instantiations.try_emplace(std::move(cpp_name)); - if (inserted) - { - it->second.guid = compute_guid_from_signature(sig); - } - }; + auto iref_coded = iref.coded_index(); + auto iref_arr_coded = iref_arr.coded_index(); - for (auto const& arg_sig : type_args) + for (auto const& type_arg : type_args) { - bool const is_object = - std::holds_alternative(arg_sig.Type()) && - std::get(arg_sig.Type()) == ElementType::Object; + // IReference + auto ireference_inst = GenericTypeInstSig{ iref_coded, std::vector{ type_arg } }; + collect_generic_inst_recursive(w, ireference_inst, {}, instantiations); - if (!is_object) - { - add_instantiation("IReference", iref_guid, arg_sig); - } - add_instantiation("IReferenceArray", iref_arr_guid, arg_sig); + // IReferenceArray + auto ireference_array_inst = GenericTypeInstSig{ iref_arr_coded, std::vector{ type_arg } }; + collect_generic_inst_recursive(w, ireference_array_inst, {}, instantiations); } + + // IReferenceArray is valid (for passing arrays of inspectable objects), + // but IReference is not (IReference boxes value types; Object is a + // reference type). So Object is not in the shared type_args list above. + auto object_arg = TypeSig{ ElementType::Object }; + auto ireference_array_object_inst = GenericTypeInstSig{ iref_arr_coded, std::vector{ object_arg } }; + collect_generic_inst_recursive(w, ireference_array_object_inst, {}, instantiations); } } From 4780fb04cee5f70a760c409854eda6d58b8ff2d5 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Fri, 29 May 2026 18:12:16 -0700 Subject: [PATCH 17/17] The problem was a pinned old version of winmd in the cmake files. --- CMakeLists.txt | 2 +- cppwinrt/helpers.h | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b0089e7ad..6e1857892 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 "" diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index 4455d5f22..aeed45279 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -1414,23 +1414,23 @@ namespace cppwinrt type_args.reserve(20); // Fundamental types - type_args.push_back(TypeSig{ ElementType::U1 }); - type_args.push_back(TypeSig{ ElementType::I2 }); - type_args.push_back(TypeSig{ ElementType::U2 }); - type_args.push_back(TypeSig{ ElementType::I4 }); - type_args.push_back(TypeSig{ ElementType::U4 }); - type_args.push_back(TypeSig{ ElementType::I8 }); - type_args.push_back(TypeSig{ ElementType::U8 }); - type_args.push_back(TypeSig{ ElementType::R4 }); - type_args.push_back(TypeSig{ ElementType::R8 }); - type_args.push_back(TypeSig{ ElementType::Char }); - type_args.push_back(TypeSig{ ElementType::Boolean }); - type_args.push_back(TypeSig{ ElementType::String }); + type_args.emplace_back(ElementType::U1); + type_args.emplace_back(ElementType::I2); + type_args.emplace_back(ElementType::U2); + type_args.emplace_back(ElementType::I4); + type_args.emplace_back(ElementType::U4); + type_args.emplace_back(ElementType::I8); + type_args.emplace_back(ElementType::U8); + type_args.emplace_back(ElementType::R4); + type_args.emplace_back(ElementType::R8); + type_args.emplace_back(ElementType::Char); + type_args.emplace_back(ElementType::Boolean); + type_args.emplace_back(ElementType::String); // Guid (only if we found the TypeRef) if (guid_type_ref) { - type_args.push_back(TypeSig{ guid_type_ref }); + type_args.emplace_back(guid_type_ref); } // Windows.Foundation struct types @@ -1440,7 +1440,7 @@ namespace cppwinrt auto td = find_type(name); if (td) { - type_args.push_back(TypeSig{ td.coded_index() }); + type_args.emplace_back(td.coded_index()); } }