From 89c9552893563819a0f0bd1d7400aea99ffba28a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 25 Oct 2024 15:33:00 -0700 Subject: [PATCH] Add 'CsWinRTDynamicallyInterfaceCastableExclusiveTo' (#1835) * Add 'CsWinRTDynamicallyInterfaceCastableExclusiveTo' * Support 'idic_exclusiveto' in code writer * Add new parameter to 'CsWinRTParams' * Fix IDIC generation, skip CCW vtable generation * Fix CCW codegen for non IDIC scenarios * Fix illegal break in code writer * Apply suggestions from code review Co-authored-by: Manodasan Wignarajah --------- Co-authored-by: Manodasan Wignarajah --- nuget/Microsoft.Windows.CsWinRT.targets | 2 ++ src/cswinrt/code_writers.h | 32 ++++++++++++++++++++----- src/cswinrt/main.cpp | 2 ++ src/cswinrt/settings.h | 1 + 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index bc2cabaac..808a27f04 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -244,6 +244,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. -embedded -public_enums -public_exclusiveto + -idic_exclusiveto $(CsWinRTCommandVerbosity) @@ -256,6 +257,7 @@ $(CsWinRTIncludeWinRTInterop) $(CsWinRTEmbeddedProjection) $(CsWinRTEmbeddedEnums) $(CsWinRTPublicExclusiveTo) +$(CsWinRTDynamicallyInterfaceCastableExclusiveTo) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 587fdb0e4..fd7cec870 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -4997,7 +4997,7 @@ remove => %.Unsubscribe(value); void write_interface_members(writer& w, TypeDef const& type) { - if (is_exclusive_to(type)) + if (is_exclusive_to(type) && !settings.idic_exclusiveto) { return; } @@ -8038,9 +8038,12 @@ NativeMemory.Free((void*)abiToProjectionVftablePtr); XLANG_ASSERT(get_category(type) == category::interface_type); auto type_name = write_type_name_temp(w, type, "%", typedef_name_type::ABI); + bool shouldOmitCcwCodegen = false; + // For exclusive interfaces which aren't overridable interfaces that are implemented by unsealed types, // we do not need any of the Do_Abi functions or the vtable logic as we will not create CCWs for them. // But we are still keeping the interface itself for any helper type lookup that may happen for like GUID lookup. + // We avoid this path if we want to generate IDIC implementations for them though. if (!is_generic && (is_exclusive_to(type) && !settings.public_exclusiveto) && // check for !authored type @@ -8066,7 +8069,17 @@ NativeMemory.Free((void*)abiToProjectionVftablePtr); if (!hasOverridableAttribute) { - w.write(R"(% + // Under normal conditions, we would stop here and just emit a minimal amount of code. + // However, if IDIC is requested, just continue normally, but omit the CCW generation. + // We know we can safely omit that because it wouldn't have normally be generated. + if (settings.idic_exclusiveto) + { + shouldOmitCcwCodegen = true; + } + else + { + // Otherwise, just write the minimal non-IDIC interface + w.write(R"(% internal interface % : % { } @@ -8074,7 +8087,9 @@ internal interface % : % bind(type), type_name, bind(type, typedef_name_type::CCW, false)); - return true; + + return true; + } } } @@ -8091,14 +8106,19 @@ internal unsafe interface % : % { %%%%} )", -// Interface abi implementation - is_exclusive_to(type) ? "" : "[DynamicInterfaceCastableImplementation]", + // Interface abi implementation + is_exclusive_to(type) && !settings.idic_exclusiveto ? "" : "[DynamicInterfaceCastableImplementation]", bind(type), type_name, bind(type, typedef_name_type::CCW, false), // Vftbl bind([&](writer& w) { + if (shouldOmitCcwCodegen) + { + return; + } + auto methods = type.MethodList(); if (is_generic) { @@ -8223,7 +8243,7 @@ AbiToProjectionVftablePtr = ComWrappersSupport.AllocateVtableMemory(typeof(@), s bind(type), "", [&](writer& w) { - if (!is_exclusive_to(type)) + if (!is_exclusive_to(type) || settings.idic_exclusiveto) { for (auto required_interface : required_interfaces) { diff --git a/src/cswinrt/main.cpp b/src/cswinrt/main.cpp index 13e298727..942d5bbf7 100644 --- a/src/cswinrt/main.cpp +++ b/src/cswinrt/main.cpp @@ -41,6 +41,7 @@ namespace cswinrt { "embedded", 0, 0, {}, "Generates an embedded projection."}, { "public_enums", 0, 0, {}, "Used with embedded option to generate enums as public"}, { "public_exclusiveto", 0, 0, {}, "Make exclusiveto interfaces public in the projection (default is internal)"}, + { "idic_exclusiveto", 0, 0, {}, "Make exclusiveto interfaces support IDynamicInterfaceCastable (IDIC) for RCW scenarios (default is false)"}, { "help", 0, option::no_max, {}, "Show detailed help" }, { "?", 0, option::no_max, {}, {} }, }; @@ -104,6 +105,7 @@ Where is one or more of: settings.embedded = args.exists("embedded"); settings.public_enums = args.exists("public_enums"); settings.public_exclusiveto = args.exists("public_exclusiveto"); + settings.idic_exclusiveto = args.exists("idic_exclusiveto"); settings.input = args.files("input", database::is_database); for (auto && include : args.values("include")) diff --git a/src/cswinrt/settings.h b/src/cswinrt/settings.h index 61fb5c40f..5b944955a 100644 --- a/src/cswinrt/settings.h +++ b/src/cswinrt/settings.h @@ -19,6 +19,7 @@ namespace cswinrt bool embedded{}; bool public_enums{}; bool public_exclusiveto{}; + bool idic_exclusiveto{}; }; extern settings_type settings;