Skip to content

Commit

Permalink
Add 'CsWinRTDynamicallyInterfaceCastableExclusiveTo' (#1835)
Browse files Browse the repository at this point in the history
* 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 <mawign@microsoft.com>

---------

Co-authored-by: Manodasan Wignarajah <mawign@microsoft.com>
  • Loading branch information
Sergio0694 and manodasanW authored Oct 25, 2024
1 parent 43e8172 commit 89c9552
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 6 deletions.
2 changes: 2 additions & 0 deletions nuget/Microsoft.Windows.CsWinRT.targets
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<CsWinRTEmbeddedProjection Condition="'$(CsWinRTEmbedded)' == 'true'">-embedded</CsWinRTEmbeddedProjection>
<CsWinRTEmbeddedEnums Condition="'$(CsWinRTEmbeddedPublicEnums)' == 'true'">-public_enums</CsWinRTEmbeddedEnums>
<CsWinRTPublicExclusiveTo Condition="'$(CsWinRTPublicExclusiveToInterfaces)' == 'true'">-public_exclusiveto</CsWinRTPublicExclusiveTo>
<CsWinRTDynamicallyInterfaceCastableExclusiveTo Condition="'$(CsWinRTDynamicallyInterfaceCastableExclusiveTo)' == 'true'">-idic_exclusiveto</CsWinRTDynamicallyInterfaceCastableExclusiveTo>

<CsWinRTParams Condition="'$(CsWinRTParams)' == ''">
$(CsWinRTCommandVerbosity)
Expand All @@ -256,6 +257,7 @@ $(CsWinRTIncludeWinRTInterop)
$(CsWinRTEmbeddedProjection)
$(CsWinRTEmbeddedEnums)
$(CsWinRTPublicExclusiveTo)
$(CsWinRTDynamicallyInterfaceCastableExclusiveTo)
</CsWinRTParams>

<CsWinRTPrivateParams Condition="'$(CsWinRTPrivateParams)' == ''">
Expand Down
32 changes: 26 additions & 6 deletions src/cswinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand All @@ -8066,15 +8069,27 @@ 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 % : %
{
}
)",
bind<write_guid_attribute>(type),
type_name,
bind<write_type_name>(type, typedef_name_type::CCW, false));
return true;

return true;
}
}
}

Expand All @@ -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<write_guid_attribute>(type),
type_name,
bind<write_type_name>(type, typedef_name_type::CCW, false),
// Vftbl
bind([&](writer& w)
{
if (shouldOmitCcwCodegen)
{
return;
}

auto methods = type.MethodList();
if (is_generic)
{
Expand Down Expand Up @@ -8223,7 +8243,7 @@ AbiToProjectionVftablePtr = ComWrappersSupport.AllocateVtableMemory(typeof(@), s
bind<write_interface_members>(type),
"",
[&](writer& w) {
if (!is_exclusive_to(type))
if (!is_exclusive_to(type) || settings.idic_exclusiveto)
{
for (auto required_interface : required_interfaces)
{
Expand Down
2 changes: 2 additions & 0 deletions src/cswinrt/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, {}, {} },
};
Expand Down Expand Up @@ -104,6 +105,7 @@ Where <spec> 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"))
Expand Down
1 change: 1 addition & 0 deletions src/cswinrt/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace cswinrt
bool embedded{};
bool public_enums{};
bool public_exclusiveto{};
bool idic_exclusiveto{};
};

extern settings_type settings;
Expand Down

0 comments on commit 89c9552

Please sign in to comment.