Skip to content

Commit 308ab65

Browse files
authored
Implement Marshal.GetIDispatchForObject on platforms with COM support (#33403)
1 parent 15ec69e commit 308ab65

File tree

14 files changed

+664
-614
lines changed

14 files changed

+664
-614
lines changed

src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,17 @@ public static string GetTypeInfoName(ITypeInfo typeInfo)
339339
[MethodImpl(MethodImplOptions.InternalCall)]
340340
internal static extern IntPtr /* IUnknown* */ GetRawIUnknownForComObjectNoAddRef(object o);
341341

342+
/// <summary>
343+
/// Return the IDispatch* for an Object.
344+
/// </summary>
345+
public static IntPtr /* IDispatch */ GetIDispatchForObject(object o)
346+
{
347+
return GetIDispatchForObjectNative(o, false);
348+
}
349+
350+
[MethodImpl(MethodImplOptions.InternalCall)]
351+
private static extern IntPtr /* IDispatch* */ GetIDispatchForObjectNative(object o, bool onlyInContext);
352+
342353
/// <summary>
343354
/// Return the IUnknown* representing the interface for the Object.
344355
/// Object o should support Type T

src/coreclr/src/vm/ecalllist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ FCFuncStart(gInteropMarshalFuncs)
820820
FCFuncElement("GetStartComSlot", MarshalNative::GetStartComSlot)
821821
FCFuncElement("GetEndComSlot", MarshalNative::GetEndComSlot)
822822
FCFuncElement("GetIUnknownForObjectNative", MarshalNative::GetIUnknownForObjectNative)
823+
FCFuncElement("GetIDispatchForObjectNative", MarshalNative::GetIDispatchForObjectNative)
823824
FCFuncElement("GetComInterfaceForObjectNative", MarshalNative::GetComInterfaceForObjectNative)
824825
FCFuncElement("InternalReleaseComObject", MarshalNative::ReleaseComObject)
825826
FCFuncElement("Release", MarshalNative::Release)

src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ private Expression MakeIDispatchInvokeTarget()
506506
Expression.Assign(
507507
DispatchPointerVariable,
508508
Expression.Call(
509-
ComRuntimeHelpers.GetGetIDispatchForObjectMethod(),
509+
typeof(Marshal).GetMethod(nameof(Marshal.GetIDispatchForObject)),
510510
DispatchObjectVariable
511511
)
512512
)

src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,6 @@ public static DispCallable CreateDispCallable(IDispatchComObject dispatch, ComMe
211211
{
212212
return new DispCallable(dispatch, method.Name, method.DispId);
213213
}
214-
215-
internal static MethodInfo GetGetIDispatchForObjectMethod()
216-
{
217-
// GetIDispatchForObject always throws a PNSE in .NET Core, so we work around it by using GetComInterfaceForObject with our IDispatch type.
218-
return typeof(Marshal).GetMethods().Single(m => m.Name == nameof(Marshal.GetComInterfaceForObject) && m.GetParameters().Length == 1 && m.ContainsGenericParameters).MakeGenericMethod(typeof(object), typeof(IDispatch));
219-
}
220214
}
221215

222216
/// <summary>

src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DispatchArgBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ internal override Expression MarshalToRef(Expression parameter)
4545
Expression.Equal(parameter, Expression.Constant(null)),
4646
Expression.Constant(IntPtr.Zero),
4747
Expression.Call(
48-
ComRuntimeHelpers.GetGetIDispatchForObjectMethod(),
48+
typeof(Marshal).GetMethod(nameof(System.Runtime.InteropServices.Marshal.GetIDispatchForObject)),
4949
parameter
5050
)
5151
);

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NoCom.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ public static IntPtr GetHINSTANCE(Module m)
9191
return (IntPtr)(-1);
9292
}
9393

94+
public static IntPtr GetIDispatchForObject(object o)
95+
{
96+
throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop);
97+
}
98+
9499
public static IntPtr GetIUnknownForObject(object o)
95100
{
96101
throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop);

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -913,8 +913,6 @@ public static int GetHRForLastWin32Error()
913913
return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
914914
}
915915

916-
public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException();
917-
918916
public static unsafe void ZeroFreeBSTR(IntPtr s)
919917
{
920918
if (s == IntPtr.Zero)

src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
<Compile Include="System\Runtime\InteropServices\Marshal\GetObjectForIUnknownTests.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
8383
<Compile Include="System\Runtime\InteropServices\Marshal\GetObjectForIUnknownTests.cs" />
8484
<Compile Include="System\Runtime\InteropServices\Marshal\GetObjectForNativeVariantTests.cs" />
85+
<Compile Include="System\Runtime\InteropServices\Marshal\GetObjectForNativeVariantTests.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
8586
<Compile Include="System\Runtime\InteropServices\Marshal\GetObjectsForNativeVariantsTests.cs" />
8687
<Compile Include="System\Runtime\InteropServices\Marshal\GetStartComSlotTests.cs" />
8788
<Compile Include="System\Runtime\InteropServices\Marshal\GetStartComSlotTests.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />

src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/DispatchWrapperTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,20 @@ public void Ctor_Null_Success()
1919
[Theory]
2020
[InlineData("")]
2121
[InlineData(0)]
22+
[PlatformSpecific(TestPlatforms.AnyUnix)]
2223
public void Ctor_NonNull_ThrowsPlatformNotSupportedException(object value)
2324
{
2425
Assert.Throws<PlatformNotSupportedException>(() => new DispatchWrapper(value));
2526
}
27+
28+
[Theory]
29+
[InlineData("")]
30+
[InlineData(0)]
31+
[PlatformSpecific(TestPlatforms.Windows)]
32+
public void Ctor_NonDispatchObject_ThrowsInvalidCastException(object value)
33+
{
34+
Assert.Throws<InvalidCastException>(() => new DispatchWrapper(value));
35+
}
2636
}
2737
#pragma warning restore 0618
2838
}

src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetIDispatchForObjectTests.Windows.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace System.Runtime.InteropServices.Tests
1010
{
1111
public partial class GetIDispatchForObjectTests
1212
{
13-
public static IEnumerable<object[]> GetIUnknownForObject_ComObject_TestData()
13+
public static IEnumerable<object[]> GetIDispatchForObject_ComObject_TestData()
1414
{
1515
yield return new object[] { new ComImportObject() };
1616

@@ -27,5 +27,20 @@ public static IEnumerable<object[]> GetIUnknownForObject_ComObject_TestData()
2727
yield return new object[] { new AutoDispatchComObjectEmpty() };
2828
yield return new object[] { new AutoDualComObjectEmpty() };
2929
}
30+
31+
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
32+
[MemberData(nameof(GetIDispatchForObject_ComObject_TestData))]
33+
public void GetIDispatchForObject_DispatchObject_Success(object obj)
34+
{
35+
IntPtr ptr = Marshal.GetIDispatchForObject(obj);
36+
try
37+
{
38+
Assert.NotEqual(IntPtr.Zero, ptr);
39+
}
40+
finally
41+
{
42+
Marshal.Release(ptr);
43+
}
44+
}
3045
}
3146
}

src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetIDispatchForObjectTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,24 @@ namespace System.Runtime.InteropServices.Tests
1313
public partial class GetIDispatchForObjectTests
1414
{
1515
[Fact]
16+
[PlatformSpecific(TestPlatforms.AnyUnix)]
1617
public void GetIDispatchForObject_NetCore_ThrowsPlatformNotSupportedException()
1718
{
1819
Assert.Throws<PlatformNotSupportedException>(() => Marshal.GetIDispatchForObject(null));
1920
}
21+
22+
[Fact]
23+
[PlatformSpecific(TestPlatforms.Windows)]
24+
public void GetIDispatchForObject_NullObject_ThrowsArgumentNullException()
25+
{
26+
AssertExtensions.Throws<ArgumentNullException>("o", () => Marshal.GetIDispatchForObject(null));
27+
}
28+
29+
[Fact]
30+
[PlatformSpecific(TestPlatforms.Windows)]
31+
public void GetIDispatchForObject_NonDispatchObject_ThrowsInvalidCastException()
32+
{
33+
Assert.Throws<InvalidCastException>(() => Marshal.GetIDispatchForObject(string.Empty));
34+
}
2035
}
2136
}

src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/GetNativeVariantForObjectTests.Windows.cs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,14 @@ public static IEnumerable<object[]> GetNativeVariantForObject_WrappedComObject_T
8080
yield return new object[] { new UnknownWrapper(autoDispatch), autoDispatch, VarEnum.VT_UNKNOWN };
8181
yield return new object[] { new UnknownWrapper(autoDual), autoDual, VarEnum.VT_UNKNOWN };
8282

83-
if (!PlatformDetection.IsNetCore)
84-
{
85-
yield return new object[] { new DispatchWrapper(empty), empty, VarEnum.VT_DISPATCH };
86-
yield return new object[] { new DispatchWrapper(dual), dual, VarEnum.VT_DISPATCH };
87-
yield return new object[] { new DispatchWrapper(iUnknown), iUnknown, VarEnum.VT_DISPATCH };
88-
yield return new object[] { new DispatchWrapper(iDispatch), iDispatch, VarEnum.VT_DISPATCH };
89-
yield return new object[] { new DispatchWrapper(iInspectable), iInspectable, VarEnum.VT_DISPATCH };
90-
yield return new object[] { new DispatchWrapper(nonDual), nonDual, VarEnum.VT_DISPATCH };
91-
yield return new object[] { new DispatchWrapper(autoDispatch), autoDispatch, VarEnum.VT_DISPATCH };
92-
yield return new object[] { new DispatchWrapper(autoDual), autoDual, VarEnum.VT_DISPATCH };
93-
}
94-
else
95-
{
96-
Assert.Throws<PlatformNotSupportedException>(() => new DispatchWrapper(10));
97-
}
83+
yield return new object[] { new DispatchWrapper(empty), empty, VarEnum.VT_DISPATCH };
84+
yield return new object[] { new DispatchWrapper(dual), dual, VarEnum.VT_DISPATCH };
85+
yield return new object[] { new DispatchWrapper(iUnknown), iUnknown, VarEnum.VT_DISPATCH };
86+
yield return new object[] { new DispatchWrapper(iDispatch), iDispatch, VarEnum.VT_DISPATCH };
87+
yield return new object[] { new DispatchWrapper(iInspectable), iInspectable, VarEnum.VT_DISPATCH };
88+
yield return new object[] { new DispatchWrapper(nonDual), nonDual, VarEnum.VT_DISPATCH };
89+
yield return new object[] { new DispatchWrapper(autoDispatch), autoDispatch, VarEnum.VT_DISPATCH };
90+
yield return new object[] { new DispatchWrapper(autoDual), autoDual, VarEnum.VT_DISPATCH };
9891
}
9992

10093
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]

0 commit comments

Comments
 (0)