From 308ab659f4098bc7df7ed3b1a87a90a209604349 Mon Sep 17 00:00:00 2001
From: Elinor Fung <47805090+elinor-fung@users.noreply.github.com>
Date: Tue, 10 Mar 2020 12:24:48 -0700
Subject: [PATCH] Implement Marshal.GetIDispatchForObject on platforms with COM
support (#33403)
---
.../Runtime/InteropServices/Marshal.CoreCLR.cs | 11 +
src/coreclr/src/vm/ecalllist.h | 1 +
.../RuntimeBinder/ComInterop/ComInvokeBinder.cs | 2 +-
.../RuntimeBinder/ComInterop/ComRuntimeHelpers.cs | 6 -
.../RuntimeBinder/ComInterop/DispatchArgBuilder.cs | 2 +-
.../Runtime/InteropServices/Marshal.NoCom.cs | 5 +
.../src/System/Runtime/InteropServices/Marshal.cs | 2 -
.../System.Runtime.InteropServices.Tests.csproj | 1 +
.../InteropServices/DispatchWrapperTests.cs | 10 +
.../Marshal/GetIDispatchForObjectTests.Windows.cs | 17 +-
.../Marshal/GetIDispatchForObjectTests.cs | 15 +
.../GetNativeVariantForObjectTests.Windows.cs | 23 +-
.../GetObjectForNativeVariantTests.Windows.cs | 594 +++++++++++++++++++++
.../Marshal/GetObjectForNativeVariantTests.cs | 589 +-------------------
14 files changed, 664 insertions(+), 614 deletions(-)
create mode 100644 src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetObjectForNativeVariantTests.Windows.cs
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs
index 9873211..07b7ce8 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs
@@ -340,6 +340,17 @@ namespace System.Runtime.InteropServices
internal static extern IntPtr /* IUnknown* */ GetRawIUnknownForComObjectNoAddRef(object o);
///
+ /// Return the IDispatch* for an Object.
+ ///
+ public static IntPtr /* IDispatch */ GetIDispatchForObject(object o)
+ {
+ return GetIDispatchForObjectNative(o, false);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern IntPtr /* IDispatch* */ GetIDispatchForObjectNative(object o, bool onlyInContext);
+
+ ///
/// Return the IUnknown* representing the interface for the Object.
/// Object o should support Type T
///
diff --git a/src/coreclr/src/vm/ecalllist.h b/src/coreclr/src/vm/ecalllist.h
index 1ae20b1..3cbfa0e 100644
--- a/src/coreclr/src/vm/ecalllist.h
+++ b/src/coreclr/src/vm/ecalllist.h
@@ -820,6 +820,7 @@ FCFuncStart(gInteropMarshalFuncs)
FCFuncElement("GetStartComSlot", MarshalNative::GetStartComSlot)
FCFuncElement("GetEndComSlot", MarshalNative::GetEndComSlot)
FCFuncElement("GetIUnknownForObjectNative", MarshalNative::GetIUnknownForObjectNative)
+ FCFuncElement("GetIDispatchForObjectNative", MarshalNative::GetIDispatchForObjectNative)
FCFuncElement("GetComInterfaceForObjectNative", MarshalNative::GetComInterfaceForObjectNative)
FCFuncElement("InternalReleaseComObject", MarshalNative::ReleaseComObject)
FCFuncElement("Release", MarshalNative::Release)
diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs
index ac48657..54bb330 100644
--- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs
+++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs
@@ -506,7 +506,7 @@ namespace Microsoft.CSharp.RuntimeBinder.ComInterop
Expression.Assign(
DispatchPointerVariable,
Expression.Call(
- ComRuntimeHelpers.GetGetIDispatchForObjectMethod(),
+ typeof(Marshal).GetMethod(nameof(Marshal.GetIDispatchForObject)),
DispatchObjectVariable
)
)
diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs
index 6b80e5f..7732a96 100644
--- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs
+++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs
@@ -211,12 +211,6 @@ namespace Microsoft.CSharp.RuntimeBinder.ComInterop
{
return new DispCallable(dispatch, method.Name, method.DispId);
}
-
- internal static MethodInfo GetGetIDispatchForObjectMethod()
- {
- // GetIDispatchForObject always throws a PNSE in .NET Core, so we work around it by using GetComInterfaceForObject with our IDispatch type.
- return typeof(Marshal).GetMethods().Single(m => m.Name == nameof(Marshal.GetComInterfaceForObject) && m.GetParameters().Length == 1 && m.ContainsGenericParameters).MakeGenericMethod(typeof(object), typeof(IDispatch));
- }
}
///
diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DispatchArgBuilder.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DispatchArgBuilder.cs
index 2d8d486..45e91dd 100644
--- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DispatchArgBuilder.cs
+++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DispatchArgBuilder.cs
@@ -45,7 +45,7 @@ namespace Microsoft.CSharp.RuntimeBinder.ComInterop
Expression.Equal(parameter, Expression.Constant(null)),
Expression.Constant(IntPtr.Zero),
Expression.Call(
- ComRuntimeHelpers.GetGetIDispatchForObjectMethod(),
+ typeof(Marshal).GetMethod(nameof(System.Runtime.InteropServices.Marshal.GetIDispatchForObject)),
parameter
)
);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NoCom.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NoCom.cs
index b310134..af94757 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NoCom.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NoCom.cs
@@ -91,6 +91,11 @@ namespace System.Runtime.InteropServices
return (IntPtr)(-1);
}
+ public static IntPtr GetIDispatchForObject(object o)
+ {
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop);
+ }
+
public static IntPtr GetIUnknownForObject(object o)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
index d7fe337..f7bbc8b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
@@ -913,8 +913,6 @@ namespace System.Runtime.InteropServices
return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
}
- public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException();
-
public static unsafe void ZeroFreeBSTR(IntPtr s)
{
if (s == IntPtr.Zero)
diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj
index 7b692de..e57c30b 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj
+++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj
@@ -82,6 +82,7 @@
+
diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/DispatchWrapperTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/DispatchWrapperTests.cs
index 9781110..4c2636d 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/DispatchWrapperTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/DispatchWrapperTests.cs
@@ -19,10 +19,20 @@ namespace System.Runtime.InteropServices.Tests
[Theory]
[InlineData("")]
[InlineData(0)]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
public void Ctor_NonNull_ThrowsPlatformNotSupportedException(object value)
{
Assert.Throws(() => new DispatchWrapper(value));
}
+
+ [Theory]
+ [InlineData("")]
+ [InlineData(0)]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void Ctor_NonDispatchObject_ThrowsInvalidCastException(object value)
+ {
+ Assert.Throws(() => new DispatchWrapper(value));
+ }
}
#pragma warning restore 0618
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetIDispatchForObjectTests.Windows.cs b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetIDispatchForObjectTests.Windows.cs
index 5109f03..ba3c0e5 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetIDispatchForObjectTests.Windows.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetIDispatchForObjectTests.Windows.cs
@@ -10,7 +10,7 @@ namespace System.Runtime.InteropServices.Tests
{
public partial class GetIDispatchForObjectTests
{
- public static IEnumerable