Skip to content

Commit

Permalink
COMObject invoke through reflection (dotnet#106677)
Browse files Browse the repository at this point in the history
A regression was introduced by implementing
IDynamicInterfaceCastable on __ComObject. This means
that the order of checks is now important. Made the
order consistent in all places and added a test for
this particular case.
  • Loading branch information
AaronRobinsonMSFT authored Aug 20, 2024
1 parent b3481b4 commit 21fe571
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 16 deletions.
32 changes: 16 additions & 16 deletions src/coreclr/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,22 @@ PTR_MethodTable InterfaceInfo_t::GetApproxMethodTable(Module * pContainingModule
MethodTable *pServerMT = (*pServer)->GetMethodTable();
PREFIX_ASSUME(pServerMT != NULL);

#ifdef FEATURE_COMINTEROP
if (pServerMT->IsComObjectType() && !pItfMD->HasMethodInstantiation())
{
// interop needs an exact MethodDesc
pItfMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
pItfMD,
ownerType.GetMethodTable(),
FALSE, // forceBoxedEntryPoint
Instantiation(), // methodInst
FALSE, // allowInstParam
TRUE); // forceRemotableMethod

RETURN(pServerMT->GetMethodDescForComInterfaceMethod(pItfMD, false));
}
#endif // !FEATURE_COMINTEROP

// For IDynamicInterfaceCastable, instead of trying to find method implementation in the real object type
// we call GetInterfaceImplementation on the object and call GetMethodDescForInterfaceMethod
// with whatever type it returns.
Expand All @@ -501,22 +517,6 @@ PTR_MethodTable InterfaceInfo_t::GetApproxMethodTable(Module * pContainingModule
RETURN(implTypeHandle.GetMethodTable()->GetMethodDescForInterfaceMethod(ownerType, pItfMD, TRUE /* throwOnConflict */));
}

#ifdef FEATURE_COMINTEROP
if (pServerMT->IsComObjectType() && !pItfMD->HasMethodInstantiation())
{
// interop needs an exact MethodDesc
pItfMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
pItfMD,
ownerType.GetMethodTable(),
FALSE, // forceBoxedEntryPoint
Instantiation(), // methodInst
FALSE, // allowInstParam
TRUE); // forceRemotableMethod

RETURN(pServerMT->GetMethodDescForComInterfaceMethod(pItfMD, false));
}
#endif // !FEATURE_COMINTEROP

// Handle pure COM+ types.
RETURN (pServerMT->GetMethodDescForInterfaceMethod(ownerType, pItfMD, TRUE /* throwOnConflict */));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace NetClient
{
using System;
using System.Reflection;
using Xunit;

class CallViaReflectionTests
{
private readonly Server.Contract.Servers.NumericTesting server;

public CallViaReflectionTests()
{
this.server = (Server.Contract.Servers.NumericTesting)new Server.Contract.Servers.NumericTestingClass();
}

public void Run()
{
Console.WriteLine(nameof(CallViaReflectionTests));
this.InvokeInstanceMethod();
}

private void InvokeInstanceMethod()
{
MethodInfo minfo = typeof(Server.Contract.INumericTesting).GetMethod("Add_Int")!;
object[] parameters = new object[2] { 10, 20 };
int sum = (int)minfo.Invoke(this.server, parameters);
Assert.Equal(30, sum);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="ArrayTests.cs" />
<Compile Include="CallViaReflectionTests.cs" />
<Compile Include="ErrorTests.cs" />
<Compile Include="NumericTests.cs" />
<Compile Include="StringTests.cs" />
Expand Down
1 change: 1 addition & 0 deletions src/tests/Interop/COM/NETClients/Primitives/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ private static void RunTests()
new StringTests().Run();
new ErrorTests().Run();
new ColorTests().Run();
new CallViaReflectionTests().Run();
}
}
}

0 comments on commit 21fe571

Please sign in to comment.