diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Marshalling/MarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Marshalling/MarshallingGenerator.cs index e9d81561b75a3..c8f13da707c3f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Marshalling/MarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Marshalling/MarshallingGenerator.cs @@ -237,6 +237,13 @@ private static IMarshallingGenerator CreateCore( { throw new MarshallingNotSupportedException(info, context); } + if (info.IsByRef && info.ManagedType.IsAbstract) + { + throw new MarshallingNotSupportedException(info, context) + { + NotSupportedDetails = Resources.SafeHandleByRefMustBeConcrete + }; + } return new SafeHandleMarshaller(options); // Marshalling in new model. diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.Designer.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.Designer.cs index e86940b256c65..87fac1a3e0ffa 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.Designer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.Designer.cs @@ -483,6 +483,15 @@ internal static string RefValuePropertyUnsupportedMessage { } } + /// + /// Looks up a localized string similar to An abstract type derived from 'SafeHandle' cannot be marshalled by reference. The provided type must be concrete.. + /// + internal static string SafeHandleByRefMustBeConcrete { + get { + return ResourceManager.GetString("SafeHandleByRefMustBeConcrete", resourceCulture); + } + } + /// /// Looks up a localized string similar to When constructor taking a Span<byte> is specified on the native type, the type must also have a public integer constant named StackBufferSize to provide the size of the stack-allocated buffer.. /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.resx b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.resx index c6a5491493395..f66d2945ad7a8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.resx @@ -259,6 +259,9 @@ The 'Value' property on the native type '{0}' must not be a 'ref' or 'readonly ref' property. + + An abstract type derived from 'SafeHandle' cannot be marshalled by reference. The provided type must be concrete. + When constructor taking a Span<byte> is specified on the native type, the type must also have a public integer constant named StackBufferSize to provide the size of the stack-allocated buffer. diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/TypePositionInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/TypePositionInfo.cs index 9cb216590cc03..0a5d4c921b22d 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/TypePositionInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/TypePositionInfo.cs @@ -312,11 +312,10 @@ static bool TryCreateTypeBasedMarshallingInfo(ITypeSymbol type, DefaultMarshalli var conversion = compilation.ClassifyCommonConversion(type, compilation.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_SafeHandle)!); if (conversion.Exists && conversion.IsImplicit - && conversion.IsReference - && !type.IsAbstract) + && (conversion.IsReference || conversion.IsIdentity)) { bool hasAccessibleDefaultConstructor = false; - if (type is INamedTypeSymbol named && named.InstanceConstructors.Length > 0) + if (type is INamedTypeSymbol named && !named.IsAbstract && named.InstanceConstructors.Length > 0) { foreach (var ctor in named.InstanceConstructors) { diff --git a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/CodeSnippets.cs index 8d630f9c2b62f..eb4cc83858fee 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/CodeSnippets.cs @@ -843,6 +843,15 @@ public static partial void Method( {byRefKind} {typeName} p); }}"; + public static string BasicParameterByValue(string typeName) => @$" +using System.Runtime.InteropServices; +partial class Test +{{ + [GeneratedDllImport(""DoesNotExist"")] + public static partial void Method( + {typeName} p); +}}"; + public static string BasicReturnType(string typeName) => @$" using System.Runtime.InteropServices; partial class Test diff --git a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/CompileFails.cs index 61f98f45fff8d..89622d1cdf233 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/CompileFails.cs @@ -92,6 +92,9 @@ public static IEnumerable CodeSnippetsToCompile() // Custom type marshalling in arrays (complex case with Value property) yield return new object[] { CodeSnippets.ArrayMarshallingWithCustomStructElementWithValueProperty, 5, 0 }; + + // Abstract SafeHandle type by reference + yield return new object[] { CodeSnippets.BasicParameterWithByRefModifier("ref", "System.Runtime.InteropServices.SafeHandle"), 1, 0 }; } [Theory] diff --git a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/Compiles.cs index 60d61de1d0b58..c9da24ff41a48 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/Compiles.cs @@ -135,6 +135,7 @@ public static IEnumerable CodeSnippetsToCompile() // SafeHandle yield return new[] { CodeSnippets.BasicParametersAndModifiers("Microsoft.Win32.SafeHandles.SafeFileHandle") }; + yield return new[] { CodeSnippets.BasicParameterByValue("System.Runtime.InteropServices.SafeHandle") }; yield return new[] { CodeSnippets.SafeHandleWithCustomDefaultConstructorAccessibility(privateCtor: false) }; yield return new[] { CodeSnippets.SafeHandleWithCustomDefaultConstructorAccessibility(privateCtor: true) };