Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ComWrappers in some Marshal unit-tests and update platform metadata #56595

Merged
merged 11 commits into from
Aug 3, 2021
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ public static void RegisterForTrackerSupport(ComWrappers instance)
/// * P/Invokes with COM-related types
/// * COM activation
/// </remarks>
[SupportedOSPlatform("windows")]
public static void RegisterForMarshalling(ComWrappers instance)
{
if (instance == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public static void RegisterForTrackerSupport(ComWrappers instance)
throw new PlatformNotSupportedException();
}

[SupportedOSPlatform("windows")]
public static void RegisterForMarshalling(ComWrappers instance)
{
throw new PlatformNotSupportedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ public enum CreateObjectFlags
/// <summary>
/// Class for managing wrappers of COM IUnknown types.
/// </summary>
[SupportedOSPlatform("windows")]
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("browser")]
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("maccatalyst")]
[UnsupportedOSPlatform("tvos")]
[CLSCompliant(false)]
public abstract partial class ComWrappers
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,11 @@ public enum CreateObjectFlags
Aggregation = 4,
Unwrap = 8,
}
[System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")]
[System.Runtime.Versioning.UnsupportedOSPlatform("android")]
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatform("maccatalyst")]
[System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
[System.CLSCompliantAttribute(false)]
public abstract class ComWrappers
{
Expand All @@ -1147,6 +1151,7 @@ public struct ComInterfaceDispatch
public object GetOrRegisterObjectForComInstance(System.IntPtr externalComObject, CreateObjectFlags flags, object wrapper, System.IntPtr inner) { throw null; }
protected abstract void ReleaseObjects(System.Collections.IEnumerable objects);
public static void RegisterForTrackerSupport(ComWrappers instance) { }
[System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")]
public static void RegisterForMarshalling(ComWrappers instance) { }
protected static void GetIUnknownImpl(out System.IntPtr fpQueryInterface, out System.IntPtr fpAddRef, out System.IntPtr fpRelease) { throw null; }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Compat issues with assembly System.Runtime.InteropServices:
TypesMustExist : Type 'System.Runtime.InteropServices.AssemblyRegistrationFlags' does not exist in the reference but it does exist in the implementation.
CannotChangeAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' on 'System.Runtime.InteropServices.ComWrappers' changed from '[UnsupportedOSPlatformAttribute("android")]' in the implementation to '[UnsupportedOSPlatformAttribute("android")]' in the reference.
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
TypesMustExist : Type 'System.Runtime.InteropServices.ExporterEventKind' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.Runtime.InteropServices.IDispatchImplAttribute' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.Runtime.InteropServices.IDispatchImplType' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.Runtime.InteropServices.RegistrationClassContext' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.Runtime.InteropServices.RegistrationConnectionType' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.Runtime.InteropServices.SetWin32ContextInIDispatchAttribute' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public void System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute..ctor()' does not exist in the reference but it does exist in the implementation.
CannotRemoveAttribute : Attribute 'System.CLSCompliantAttribute' exists on 'System.Runtime.InteropServices.ComTypes.IDataObject' in the implementation but not the reference.
Total Issues: 9
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
<Compile Include="System\Runtime\InteropServices\Marshal\ZeroFreeGlobalAllocAnsiTests.cs" />
<Compile Include="System\Runtime\InteropServices\Marshal\ZeroFreeGlobalAllocUnicodeTests.cs" />
<Compile Include="System\Runtime\InteropServices\Marshal\Common\CommonTypes.cs" />
<Compile Include="System\Runtime\InteropServices\Marshal\Common\COMWrappersImpl.cs" />
<Compile Include="System\Runtime\InteropServices\Marshal\Common\CommonTypes.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
<Compile Include="System\Runtime\InteropServices\Marshal\Common\Variant.cs" />
<Compile Include="System\Runtime\InteropServices\Marshal\ReadWrite\ByteTests.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices.Tests.Common;
using Xunit;

namespace System.Runtime.InteropServices.Tests
{
public class AddRefTests
{
[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
[SkipOnMono("ComWrappers are not supported on Mono")]
public void AddRef_ValidPointer_Success()
{
IntPtr iUnknown = Marshal.GetIUnknownForObject(new object());
var cw = new ComWrappersImpl();
IntPtr iUnknown = cw.GetOrCreateComInterfaceForObject(new object(), CreateComInterfaceFlags.None);
try
{
Assert.Equal(2, Marshal.AddRef(iUnknown));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Runtime.CompilerServices;
using Xunit;

namespace System.Runtime.InteropServices.Tests.Common
{
public class ComWrappersImpl : ComWrappers
{
// Doesn't represent a real interface. The value is only used to support a call to QueryInterface for testing.
public const string IID_TestQueryInterface = "1F906666-B388-4729-B78C-826BC5FD4245";
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved

protected unsafe override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count)
{
Assert.Equal(CreateComInterfaceFlags.None, flags);

IntPtr fpQueryInterface = default;
IntPtr fpAddRef = default;
IntPtr fpRelease = default;
ComWrappers.GetIUnknownImpl(out fpQueryInterface, out fpAddRef, out fpRelease);

var vtblRaw = (IntPtr*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ComWrappersImpl), IntPtr.Size * 3);
vtblRaw[0] = fpQueryInterface;
vtblRaw[1] = fpAddRef;
vtblRaw[2] = fpRelease;

var entryRaw = (ComInterfaceEntry*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ComWrappersImpl), sizeof(ComInterfaceEntry));
entryRaw->IID = new Guid(IID_TestQueryInterface);
entryRaw->Vtable = (IntPtr)vtblRaw;

count = 1;
return entryRaw;
}

protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flag)
=> throw new NotImplementedException();

protected override void ReleaseObjects(IEnumerable objects)
=> throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace System.Runtime.InteropServices.Tests
{
public partial class QueryInterfaceTests
{
public const string IID_IDISPATCH = "00020400-0000-0000-C000-000000000046";
public const string IID_IINSPECTABLE = "AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90";

public static IEnumerable<object[]> QueryInterface_ValidComObjectInterface_TestData()
Expand Down Expand Up @@ -45,7 +46,25 @@ public static IEnumerable<object[]> QueryInterface_ValidComObjectInterface_TestD
[MemberData(nameof(QueryInterface_ValidComObjectInterface_TestData))]
public void QueryInterface_ValidComObjectInterface_Success(object o, string iidString)
{
QueryInterface_ValidInterface_Success(o, iidString);
IntPtr ptr = Marshal.GetIUnknownForObject(o);
try
{
Guid guid = new Guid(iidString);
Assert.Equal(0, Marshal.QueryInterface(ptr, ref guid, out IntPtr ppv));
Assert.NotEqual(IntPtr.Zero, ppv);
try
{
Assert.Equal(new Guid(iidString), guid);
}
finally
{
Marshal.Release(ppv);
}
}
finally
{
Marshal.Release(ptr);
}
}

public static IEnumerable<object[]> QueryInterface_NoSuchComObjectInterface_TestData()
Expand Down Expand Up @@ -83,7 +102,18 @@ public static IEnumerable<object[]> QueryInterface_NoSuchComObjectInterface_Test
[MemberData(nameof(QueryInterface_NoSuchComObjectInterface_TestData))]
public void QueryInterface_NoSuchComObjectInterface_Success(object o, string iidString)
{
QueryInterface_NoSuchInterface_Success(o, iidString);
IntPtr ptr = Marshal.GetIUnknownForObject(o);
try
{
Guid iid = new Guid(iidString);
Assert.Equal(E_NOINTERFACE, Marshal.QueryInterface(ptr, ref iid, out IntPtr ppv));
Assert.Equal(IntPtr.Zero, ppv);
Assert.Equal(new Guid(iidString), iid);
}
finally
{
Marshal.Release(ptr);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,71 +12,28 @@ public partial class QueryInterfaceTests
{
public const int E_NOINTERFACE = unchecked((int)0x80004002);
public const string IID_IUNKNOWN = "00000000-0000-0000-C000-000000000046";
public const string IID_IDISPATCH = "00020400-0000-0000-C000-000000000046";

public static IEnumerable<object[]> QueryInterface_ValidInterface_TestData()
{
yield return new object[] { new object(), IID_IUNKNOWN };
yield return new object[] { new object(), IID_IDISPATCH };

yield return new object[] { 10, IID_IUNKNOWN };
if (!PlatformDetection.IsNetCore)
{
yield return new object[] { 10, IID_IDISPATCH };
}

yield return new object[] { "string", IID_IUNKNOWN };
if (!PlatformDetection.IsNetCore)
{
yield return new object[] { "string", IID_IDISPATCH };
}

yield return new object[] { new NonGenericClass(), IID_IUNKNOWN };
if (!PlatformDetection.IsNetCore)
{
yield return new object[] { new NonGenericClass(), IID_IDISPATCH };
}
yield return new object[] { new GenericClass<string>(), IID_IUNKNOWN };

yield return new object[] { new NonGenericStruct(), IID_IUNKNOWN };
if (!PlatformDetection.IsNetCore)
{
yield return new object[] { new NonGenericStruct(), IID_IDISPATCH };
}
yield return new object[] { new GenericStruct<string>(), IID_IUNKNOWN };

yield return new object[] { Int32Enum.Value1, IID_IUNKNOWN };
if (!PlatformDetection.IsNetCore)
{
yield return new object[] { Int32Enum.Value1, IID_IDISPATCH };
}

yield return new object[] { new int[] { 10 }, IID_IUNKNOWN };
yield return new object[] { new int[][] { new int[] { 10 } }, IID_IUNKNOWN };
yield return new object[] { new int[,] { { 10 } }, IID_IUNKNOWN };

MethodInfo method = typeof(GetObjectForIUnknownTests).GetMethod(nameof(NonGenericMethod), BindingFlags.NonPublic | BindingFlags.Static);
Delegate d = method.CreateDelegate(typeof(NonGenericDelegate));
yield return new object[] { d, IID_IUNKNOWN };
yield return new object[] { d, IID_IDISPATCH };

yield return new object[] { new KeyValuePair<string, int>("key", 10), IID_IUNKNOWN };
yield return new object[] { new object(), ComWrappersImpl.IID_TestQueryInterface };
}

[Theory]
[MemberData(nameof(QueryInterface_ValidInterface_TestData))]
[PlatformSpecific(TestPlatforms.Windows)]
public void QueryInterface_ValidInterface_Success(object o, string guid)
[SkipOnMono("ComWrappers are not supported on Mono")]
public void QueryInterface_ValidInterface_Success(object o, string iidString)
{
IntPtr ptr = Marshal.GetIUnknownForObject(o);
var cw = new ComWrappersImpl();
IntPtr ptr = cw.GetOrCreateComInterfaceForObject(o, CreateComInterfaceFlags.None);
try
{
Guid iidString = new Guid(guid);
Assert.Equal(0, Marshal.QueryInterface(ptr, ref iidString, out IntPtr ppv));
Guid guid = new Guid(iidString);
Assert.Equal(0, Marshal.QueryInterface(ptr, ref guid, out IntPtr ppv));
Assert.NotEqual(IntPtr.Zero, ppv);
try
{
Assert.Equal(new Guid(guid), iidString);
Assert.Equal(new Guid(iidString), guid);
}
finally
{
Expand All @@ -93,23 +50,15 @@ public static IEnumerable<object[]> QueryInterface_NoSuchInterface_TestData()
{
yield return new object[] { new object(), Guid.Empty.ToString() };
yield return new object[] { new object(), "927971f5-0939-11d1-8be1-00c04fd8d503" };

yield return new object[] { new int[] { 10 }, IID_IDISPATCH };
yield return new object[] { new int[][] { new int[] { 10 } }, IID_IDISPATCH };
yield return new object[] { new int[,] { { 10 } }, IID_IDISPATCH };

yield return new object[] { new GenericClass<string>(), IID_IDISPATCH };
yield return new object[] { new Dictionary<string, int>(), IID_IDISPATCH };
yield return new object[] { new GenericStruct<string>(), IID_IDISPATCH };
yield return new object[] { new KeyValuePair<string, int>(), IID_IDISPATCH };
}

[Theory]
[MemberData(nameof(QueryInterface_NoSuchInterface_TestData))]
[PlatformSpecific(TestPlatforms.Windows)]
[SkipOnMono("ComWrappers are not supported on Mono")]
public void QueryInterface_NoSuchInterface_Success(object o, string iidString)
{
IntPtr ptr = Marshal.GetIUnknownForObject(o);
var cw = new ComWrappersImpl();
IntPtr ptr = cw.GetOrCreateComInterfaceForObject(o, CreateComInterfaceFlags.None);
try
{
Guid iid = new Guid(iidString);
Expand All @@ -129,10 +78,5 @@ public void QueryInterface_ZeroPointer_ThrowsArgumentNullException()
Guid iid = Guid.Empty;
AssertExtensions.Throws<ArgumentNullException>("pUnk", () => Marshal.QueryInterface(IntPtr.Zero, ref iid, out IntPtr ppv));
}

private static void NonGenericMethod(int i) { }
public delegate void NonGenericDelegate(int i);

public enum Int32Enum : int { Value1, Value2 }
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices.Tests.Common;
using Xunit;

namespace System.Runtime.InteropServices.Tests
{
public class ReleaseTests
{
[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
[SkipOnMono("ComWrappers are not supported on Mono")]
public void Release_ValidPointer_Success()
{
IntPtr iUnknown = Marshal.GetIUnknownForObject(new object());
var cw = new ComWrappersImpl();
IntPtr iUnknown = cw.GetOrCreateComInterfaceForObject(new object(), CreateComInterfaceFlags.None);
try
{
Marshal.AddRef(iUnknown);
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/shims/ApiCompat.proj
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
<Output TaskParameter="ExitCode" PropertyName="ApiCompatExitCode" />
</Exec>

<Error Condition="'$(ApiCompatExitCode)' != '0'" Text="ApiCompat failed comparing $(PreviousNetCoreApp) to $(NetCoreAppCurrent)" />
<Error Condition="'$(ApiCompatExitCode)' != '0'" Text="ApiCompat failed comparing $(PreviousNetCoreApp) to $(NetCoreAppCurrent). If this breaking change is intentional, the ApiCompat baseline can be updated by running 'dotnet build $(MSBuildThisFileFullPath) /p:UpdatePreviousNetCoreAppBaseline=true'" />
</Target>

<Target Name="CleanAdditionalFiles" AfterTargets="Clean">
Expand Down
Loading