未验证 提交 21f80782 编写于 作者: A Andrii Kurdiumov 提交者: GitHub

NativeAOT: ICustomMarshaller (#62921)

* NativeAOT: ICustomMarshaller

This is https://github.com/dotnet/runtimelab/pull/1723/files without issues.targets change

* Fix all newly added tests

* Make TypeLoadException more consistent with CoreCLR

* Do not enable Interop/ICustomMarshaler/Primitives/ICustomMarshaler_TargetWindows

* Mark tests according to the passing status

* Add proper feature check

* Rename SupportsComInterop to SupportsExceptionInterop
Co-authored-by: NMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
上级 04bcc055
......@@ -2,14 +2,17 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Reflection;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
using Internal.Runtime;
using Internal.Runtime.Augments;
namespace Internal.Runtime.CompilerHelpers
......@@ -591,6 +594,32 @@ internal static unsafe void CleanupVariant(IntPtr pDstNativeVariant)
#endif
}
public static unsafe object InitializeCustomMarshaller(RuntimeTypeHandle pParameterType, RuntimeTypeHandle pMarshallerType, string cookie, delegate*<string, object> getInstanceMethod)
{
if (getInstanceMethod == null)
{
throw new ApplicationException();
}
if (!RuntimeImports.AreTypesAssignable(pMarshallerType.ToEETypePtr(), EETypePtr.EETypePtrOf<ICustomMarshaler>()))
{
throw new ApplicationException();
}
var marshaller = CustomMarshallerTable.s_customMarshallersTable.GetOrAdd(new CustomMarshallerKey(pParameterType, pMarshallerType, cookie, getInstanceMethod));
if (marshaller == null)
{
throw new ApplicationException();
}
if (!RuntimeImports.AreTypesAssignable(marshaller.EETypePtr, EETypePtr.EETypePtrOf<ICustomMarshaler>()))
{
throw new ApplicationException();
}
return marshaller;
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct ModuleFixupCell
{
......@@ -608,5 +637,52 @@ internal unsafe struct MethodFixupCell
public ModuleFixupCell* Module;
public CharSet CharSetMangling;
}
internal unsafe struct CustomMarshallerKey : IEquatable<CustomMarshallerKey>
{
public CustomMarshallerKey(RuntimeTypeHandle pParameterType, RuntimeTypeHandle pMarshallerType, string cookie, delegate*<string, object> getInstanceMethod)
{
ParameterType = pParameterType;
MarshallerType = pMarshallerType;
Cookie = cookie;
GetInstanceMethod = getInstanceMethod;
}
public RuntimeTypeHandle ParameterType { get; }
public RuntimeTypeHandle MarshallerType { get; }
public string Cookie { get; }
public delegate*<string, object> GetInstanceMethod { get; }
public override bool Equals(object obj)
{
if (!(obj is CustomMarshallerKey other))
return false;
return Equals(other);
}
public bool Equals(CustomMarshallerKey other)
{
return ParameterType.Equals(other.ParameterType)
&& MarshallerType.Equals(other.MarshallerType)
&& Cookie.Equals(other.Cookie);
}
public override int GetHashCode()
{
return ParameterType.GetHashCode()
^ MarshallerType.GetHashCode()
^ Cookie.GetHashCode();
}
}
internal sealed class CustomMarshallerTable : ConcurrentUnifier<CustomMarshallerKey, object>
{
internal static CustomMarshallerTable s_customMarshallersTable = new CustomMarshallerTable();
protected unsafe override object Factory(CustomMarshallerKey key)
{
return key.GetInstanceMethod(key.Cookie);
}
}
}
}
......@@ -535,6 +535,8 @@ public MarshalAsDescriptor ParseMarshalAsDescriptor()
NativeTypeKind type = (NativeTypeKind)_reader.ReadByte();
NativeTypeKind arraySubType = NativeTypeKind.Default;
uint? paramNum = null, numElem = null;
string cookie = null;
TypeDesc marshallerType = null;
switch (type)
{
......@@ -607,9 +609,6 @@ public MarshalAsDescriptor ParseMarshalAsDescriptor()
break;
case NativeTypeKind.CustomMarshaler:
{
// There's nobody to consume CustomMarshaller, so let's just parse the data
// to avoid asserting later.
// Read typelib guid
_reader.ReadSerializedString();
......@@ -617,10 +616,11 @@ public MarshalAsDescriptor ParseMarshalAsDescriptor()
_reader.ReadSerializedString();
// Read managed marshaler name
_reader.ReadSerializedString();
var customMarshallerTypeName = _reader.ReadSerializedString();
marshallerType = _ecmaModule.GetTypeByCustomAttributeTypeName(customMarshallerTypeName, true);
// Read cookie
_reader.ReadSerializedString();
cookie = _reader.ReadSerializedString();
}
break;
default:
......@@ -629,7 +629,7 @@ public MarshalAsDescriptor ParseMarshalAsDescriptor()
Debug.Assert(_reader.RemainingBytes == 0);
return new MarshalAsDescriptor(type, arraySubType, paramNum, numElem);
return new MarshalAsDescriptor(type, arraySubType, paramNum, numElem, marshallerType, cookie);
}
}
}
......@@ -173,6 +173,9 @@ public static partial class MarshalHelpers
#if !READYTORUN
case MarshallerKind.Variant:
return InteropTypes.GetVariant(context);
case MarshallerKind.CustomMarshaler:
return context.GetWellKnownType(WellKnownType.IntPtr);
#endif
case MarshallerKind.OleCurrency:
......@@ -249,6 +252,14 @@ public static partial class MarshalHelpers
if (marshalAs != null)
nativeType = marshalAs.Type;
if (nativeType == NativeTypeKind.CustomMarshaler)
{
if (isField)
return MarshallerKind.FailedTypeLoad;
else
return MarshallerKind.CustomMarshaler;
}
//
// Determine MarshalerKind
//
......@@ -574,6 +585,9 @@ public static partial class MarshalHelpers
case NativeTypeKind.AnsiBStr:
return MarshallerKind.AnsiBSTRString;
case NativeTypeKind.CustomMarshaler:
return MarshallerKind.CustomMarshaler;
case NativeTypeKind.Default:
if (isAnsi)
return MarshallerKind.AnsiString;
......@@ -663,7 +677,9 @@ public static partial class MarshalHelpers
return MarshallerKind.Invalid;
}
else
{
return MarshallerKind.Invalid;
}
}
private static MarshallerKind GetArrayElementMarshallerKind(
......@@ -834,6 +850,8 @@ public static partial class MarshalHelpers
return MarshallerKind.BSTRString;
case NativeTypeKind.AnsiBStr:
return MarshallerKind.AnsiBSTRString;
case NativeTypeKind.CustomMarshaler:
return MarshallerKind.CustomMarshaler;
default:
return MarshallerKind.Invalid;
}
......
......@@ -90,6 +90,8 @@ protected static Marshaller CreateMarshaller(MarshallerKind kind)
return new FailedTypeLoadMarshaller();
case MarshallerKind.Variant:
return new VariantMarshaller();
case MarshallerKind.CustomMarshaler:
return new CustomTypeMarshaller();
default:
// ensures we don't throw during create marshaller. We will throw NSE
// during EmitIL which will be handled and an Exception method body
......@@ -1144,4 +1146,136 @@ protected override void EmitCleanupManaged(ILCodeStream codeStream)
codeStream.Emit(ILOpcode.call, emitter.NewToken(helper));
}
}
class CustomTypeMarshaller : Marshaller
{
private ILLocalVariable MarshallerLocalVariable = (ILLocalVariable)(-1);
private ILLocalVariable InitializeMarshallerVariable()
{
if (MarshallerLocalVariable != (ILLocalVariable)(-1))
{
return MarshallerLocalVariable;
}
var marshallerType = MarshalAsDescriptor.MarshallerType;
if (marshallerType.IsGenericDefinition)
{
ThrowHelper.ThrowTypeLoadException(marshallerType);
}
var customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler");
var getInstanceMethod = marshallerType.GetMethod(
"GetInstance",
new MethodSignature(MethodSignatureFlags.Static, 0, customMarshallerType, new[] { Context.GetWellKnownType(WellKnownType.String) }));
if (ManagedType.IsValueType || ManagedType.IsPointer || ManagedType.IsFunctionPointer)
{
ThrowHelper.ThrowMarshalDirectiveException();
}
var initializeCustomMarshallerMethod = Context.GetHelperEntryPoint("InteropHelpers", "InitializeCustomMarshaller");
ILEmitter emitter = _ilCodeStreams.Emitter;
MarshallerLocalVariable = emitter.NewLocal(customMarshallerType);
var cookie = MarshalAsDescriptor.Cookie;
// Custom marshaller initialization should not be catched, so initialize early
ILCodeStream fnptrLoadStream = _ilCodeStreams.FunctionPointerLoadStream;
fnptrLoadStream.Emit(ILOpcode.ldtoken, emitter.NewToken(ManagedType));
fnptrLoadStream.Emit(ILOpcode.ldtoken, emitter.NewToken(marshallerType));
fnptrLoadStream.Emit(ILOpcode.ldstr, emitter.NewToken(cookie));
if (getInstanceMethod != null)
{
fnptrLoadStream.Emit(ILOpcode.ldftn, emitter.NewToken(getInstanceMethod));
}
else
{
fnptrLoadStream.EmitLdc(0);
fnptrLoadStream.Emit(ILOpcode.conv_i);
}
fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(initializeCustomMarshallerMethod));
fnptrLoadStream.EmitStLoc(MarshallerLocalVariable);
return MarshallerLocalVariable;
}
protected override void TransformManagedToNative(ILCodeStream codeStream)
{
var lMarshaller = InitializeMarshallerVariable();
var customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler");
ILEmitter emitter = _ilCodeStreams.Emitter;
var manageToNativeMethod = customMarshallerType.GetKnownMethod(
"MarshalManagedToNative",
new MethodSignature(MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.IntPtr), new[] { Context.GetWellKnownType(WellKnownType.Object) }));
codeStream.EmitLdLoc(lMarshaller);
LoadManagedValue(codeStream);
codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(manageToNativeMethod));
StoreNativeValue(codeStream);
if (MarshalDirection == MarshalDirection.Forward)
{
if (In && Out)
{
EmitCleanUpManagedData(codeStream);
}
EmitCleanUpNativeData(_ilCodeStreams.CleanupCodeStream);
}
else
{
EmitCleanUpManagedData(codeStream);
}
}
protected override void TransformNativeToManaged(ILCodeStream codeStream)
{
var lMarshaller = InitializeMarshallerVariable();
var customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler");
ILEmitter emitter = _ilCodeStreams.Emitter;
var marshalNativeToManagedMethod = customMarshallerType.GetKnownMethod(
"MarshalNativeToManaged",
new MethodSignature(MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.Object), new[] { Context.GetWellKnownType(WellKnownType.IntPtr) }));
codeStream.EmitLdLoc(lMarshaller);
LoadNativeValue(codeStream);
codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(marshalNativeToManagedMethod));
StoreManagedValue(codeStream);
}
protected void EmitCleanUpManagedData(ILCodeStream codeStream)
{
var lMarshaller = InitializeMarshallerVariable();
var customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler");
ILEmitter emitter = _ilCodeStreams.Emitter;
// Call CleanUpManagedData on cleanup code stream.
var cleanupManagedDataMethod = customMarshallerType.GetKnownMethod(
"CleanUpManagedData",
new MethodSignature(MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.Void), new[] { Context.GetWellKnownType(WellKnownType.Object) }));
codeStream.EmitLdLoc(lMarshaller);
LoadManagedValue(codeStream);
codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(cleanupManagedDataMethod));
}
protected void EmitCleanUpNativeData(ILCodeStream codeStream)
{
var lMarshaller = InitializeMarshallerVariable();
var customMarshallerType = Context.SystemModule.GetKnownType("System.Runtime.InteropServices", "ICustomMarshaler");
ILEmitter emitter = _ilCodeStreams.Emitter;
// Call CleanUpNativeData on cleanup code stream.
var cleanupNativeDataMethod = customMarshallerType.GetKnownMethod(
"CleanUpNativeData",
new MethodSignature(MethodSignatureFlags.None, 0, Context.GetWellKnownType(WellKnownType.Void), new[] { Context.GetWellKnownType(WellKnownType.IntPtr) }));
codeStream.EmitLdLoc(lMarshaller);
LoadNativeValue(codeStream);
codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(cleanupNativeDataMethod));
}
}
}
......@@ -48,6 +48,7 @@ enum MarshallerKind
FailedTypeLoad,
ComInterface,
BlittableValueClassWithCopyCtor,
CustomMarshaler,
Invalid
}
......
......@@ -3,6 +3,7 @@
using System.Runtime.CompilerServices;
using System;
using System.Diagnostics;
namespace Internal.TypeSystem
{
......@@ -48,17 +49,39 @@ public enum NativeTypeKind : byte
public class MarshalAsDescriptor
{
private TypeDesc _marshallerType;
private string _cookie;
public NativeTypeKind Type { get; }
public NativeTypeKind ArraySubType { get; }
public uint? SizeParamIndex { get; }
public uint? SizeConst { get; }
public TypeDesc MarshallerType
{
get
{
Debug.Assert(Type == NativeTypeKind.CustomMarshaler, "Marshaller type can be set only when using for CustomMarshaller");
return _marshallerType;
}
}
public string Cookie
{
get
{
Debug.Assert(Type == NativeTypeKind.CustomMarshaler, "Cookie can be set only when using for CustomMarshaller");
return _cookie;
}
}
public MarshalAsDescriptor(NativeTypeKind type, NativeTypeKind arraySubType, uint? sizeParamIndex, uint? sizeConst)
public MarshalAsDescriptor(NativeTypeKind type, NativeTypeKind arraySubType, uint? sizeParamIndex, uint? sizeConst, TypeDesc customMarshallerType, string cookie)
{
Type = type;
ArraySubType = arraySubType;
SizeParamIndex = sizeParamIndex;
SizeConst = sizeConst;
_marshallerType = customMarshallerType;
_cookie = cookie;
}
}
}
......@@ -91,6 +91,17 @@ public static bool IsWindowsIoTCore
// return whether or not the OS is a 64 bit OS
public static bool Is64 => (IntPtr.Size == 8);
public static bool IsMonoRuntime => Type.GetType("Mono.RuntimeStructs") != null;
public static bool IsNotMonoRuntime => !IsMonoRuntime;
public static bool IsNativeAot => IsNotMonoRuntime && !IsReflectionEmitSupported;
#if NETCOREAPP
public static bool IsReflectionEmitSupported => RuntimeFeature.IsDynamicCodeSupported;
public static bool IsNotReflectionEmitSupported => !IsReflectionEmitSupported;
#else
public static bool IsReflectionEmitSupported => true;
#endif
public static bool SupportsExceptionInterop => IsWindows && IsNotMonoRuntime && !IsNativeAot; // matches definitions in clr.featuredefines.props
public static string ByteArrayToString(byte[] bytes)
{
StringBuilder sb = new StringBuilder();
......
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using Xunit;
using static TestLibrary.Utilities;
namespace System.Runtime.InteropServices.Tests
{
......@@ -167,11 +168,10 @@ public static void Parameter_CustomMarshalerProvided_CallsMethodsInCorrectOrderi
// GetInstance is only called once.
string val3 = "7488";
Assert.Equal(val3, OrderTrackingMethodRef(ref val3));
Assert.Equal(7488, OrderTrackingMethodRef(ref val3));
IEnumerable<string> expectedOrderingThirdCall = expectedOrderingSecondCall.Concat(new string[]
{
"Called MarshalManagedToNative",
"Called MarshalNativeToManaged",
"Called CleanUpManagedData",
"Called MarshalNativeToManaged",
"Called CleanUpNativeData",
......@@ -184,7 +184,7 @@ public static void Parameter_CustomMarshalerProvided_CallsMethodsInCorrectOrderi
{
"Called MarshalNativeToManaged",
});
Assert.Equal(expectedOrderingForthCall.Skip(12), OrderTrackingCustomMarshaler.Events.Skip(12));
Assert.Equal(expectedOrderingForthCall.Skip(11), OrderTrackingCustomMarshaler.Events.Skip(11));
var val5 = OrderTrackingMethodDelegate(439, (x) => x.ToString());
Assert.Equal("439", val5);
......@@ -194,7 +194,15 @@ public static void Parameter_CustomMarshalerProvided_CallsMethodsInCorrectOrderi
"Called CleanUpManagedData",
"Called MarshalNativeToManaged",
});
Assert.Equal(expectedOrderingFifthCall.Skip(13), OrderTrackingCustomMarshaler.Events.Skip(13));
Assert.Equal(expectedOrderingFifthCall.Skip(12), OrderTrackingCustomMarshaler.Events.Skip(12));
var val6 = OrderTrackingMethodReturn("726");
Assert.Equal("726", val6);
IEnumerable<string> expectedOrderingSixthCall = expectedOrderingFifthCall.Concat(new string[]
{
"Called MarshalNativeToManaged",
});
Assert.Equal(expectedOrderingSixthCall.Skip(15), OrderTrackingCustomMarshaler.Events.Skip(15));
}
// This should only be used *once*, as it uses static state.
......@@ -248,8 +256,7 @@ public static ICustomMarshaler GetInstance(string cookie)
public static extern string OrderTrackingMethod([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(OrderTrackingCustomMarshaler))] string str);
[DllImport("CustomMarshalersPrimitives", EntryPoint = "NativeParseIntRef")]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(OrderTrackingCustomMarshaler))]
public static extern string OrderTrackingMethodRef([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(OrderTrackingCustomMarshaler))] ref string str);
public static extern int OrderTrackingMethodRef([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(OrderTrackingCustomMarshaler))] ref string str);
[DllImport("CustomMarshalersPrimitives", EntryPoint = "NativeParseIntOut")]
public static extern void OrderTrackingMethodOut([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(OrderTrackingCustomMarshaler))] out string str);
......@@ -261,6 +268,10 @@ public static ICustomMarshaler GetInstance(string cookie)
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(OrderTrackingCustomMarshaler))]
public static extern string OrderTrackingMethodDelegate(int val, TestDelegate dlg);
[DllImport("CustomMarshalersPrimitives", EntryPoint = "NativeParseInt")]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(OrderTrackingCustomMarshaler))]
public static extern string OrderTrackingMethodReturn([MarshalAs(UnmanagedType.LPStr)] string str);
public static void CustomMarshaler_BothMarshalTypeRefAndMarshalTypeProvided_PicksMarshalType()
{
Assert.Equal(2, BothTypeRefAndTypeMethod("64001"));
......@@ -392,6 +403,14 @@ public static void Parameter_NullICustomMarshaler_ThrowsTypeLoadException()
[DllImport(LibcLibrary, EntryPoint = "atoi", CallingConvention = CallingConvention.Cdecl)]
public static extern int NullCustomMarshalerMethod([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = null)] string str);
public static void Parameter_InvalidTypeICustomMarshaler_TypeLoadException()
{
Assert.Throws<TypeLoadException>(() => InvalidTypeCustomMarshalerMethod(""));
}
[DllImport(LibcLibrary, EntryPoint = "atoi", CallingConvention = CallingConvention.Cdecl)]
public static extern int InvalidTypeCustomMarshalerMethod([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "junk_type")] string str);
public static void Parameter_NotICustomMarshaler_ThrowsApplicationException()
{
Assert.Throws<ApplicationException>(() => NonICustomMarshalerMethod(""));
......@@ -658,11 +677,9 @@ private class InnerCustomMarshaler : ILargeInterface, ICustomMarshaler
[DllImport(LibcLibrary, EntryPoint = "atoi", CallingConvention = CallingConvention.Cdecl)]
public static extern int DifferentCustomMarshalerType([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(OuterCustomMarshaler))] string str);
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BoxedValueTypeCustomMarshaler))]
public delegate string TestDelegateRef([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BoxedValueTypeCustomMarshaler))] ref int val);
[DllImport("CustomMarshalersPrimitives", EntryPoint = "NativeParseIntDelegateRef")]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BoxedValueTypeCustomMarshaler))]
public static extern string CustomMarshallerWithDelegateRef(int val, TestDelegateRef dlg);
public static void DelegateParameter_MarshalerOnRefInt_ThrowsMarshalDirectiveException()
......@@ -686,6 +703,7 @@ public static int Main(String[] args)
Parameter_MarshalerOnValueType_ThrowsMarshalDirectiveException();
Parameter_MarshalerOnPointer_ThrowsMarshalDirectiveException();
Parameter_NullICustomMarshaler_ThrowsTypeLoadException();
Parameter_InvalidTypeICustomMarshaler_TypeLoadException();
Parameter_NotICustomMarshaler_ThrowsApplicationException();
Parameter_OpenGenericICustomMarshaler_ThrowsTypeLoadException();
Parameter_GetInstanceMethodDoesntExist_ThrowsApplicationException();
......@@ -699,7 +717,11 @@ public static int Main(String[] args)
Parameter_CleanUpNativeDataMethodThrows_ThrowsActualException();
Field_ParentIsStruct_ThrowsTypeLoadException();
Parameter_DifferentCustomMarshalerType_MarshalsCorrectly();
DelegateParameter_MarshalerOnRefInt_ThrowsMarshalDirectiveException();
if (SupportsExceptionInterop)
{
// EH interop is not supported for NativeAOT.
DelegateParameter_MarshalerOnRefInt_ThrowsMarshalDirectiveException();
}
}
catch (Exception e)
{
......
......@@ -893,12 +893,6 @@
<ExcludeList Include="$(XunitTestBinBase)/Interop/ICustomMarshaler/ConflictingNames/MultipleALCs/*">
<Issue>https://github.com/dotnet/runtimelab/issues/155: AssemblyLoadContext.LoadFromAssemblyPath</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/ICustomMarshaler/ConflictingNames/SameNameDifferentAssembly/*">
<Issue>https://github.com/dotnet/runtimelab/issues/160</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/ICustomMarshaler/Primitives/ICustomMarshaler_TargetWindows/*">
<Issue>https://github.com/dotnet/runtimelab/issues/160</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/**/*">
<Issue>https://github.com/dotnet/runtimelab/issues/155: C++/CLI</Issue>
</ExcludeList>
......@@ -945,7 +939,7 @@
<Issue>https://github.com/dotnet/runtimelab/issues/173</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/PInvoke/CustomMarshalers/CustomMarshalersTest/*">
<Issue>https://github.com/dotnet/runtimelab/issues/160</Issue>
<Issue>Specific to CoreCLR: Built-in COM Interop</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/PInvoke/Decimal/DecimalTest/*">
<Issue>https://github.com/dotnet/runtimelab/issues/175</Issue>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册