Skip to content

Expose the custom type marshalling types for source-generated interop. #67052

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions eng/generators.targets
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,6 @@
<Compile Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' != '$(TargetFrameworkMoniker)'"
Include="$(CoreLibSharedDir)System\Runtime\InteropServices\StringMarshalling.cs" />

<!-- Only add the following files if we are on the latest TFM (that is, net7). -->
<Compile Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)'"
Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\GeneratedMarshallingAttribute.cs" />
<Compile Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)'"
Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerKind.cs" />
<Compile Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)'"
Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerDirection.cs" />
<Compile Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)'"
Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerFeatures.cs" />

<!-- Only add the following files if we are on the latest TFM (that is, net7) and the project is SPCL or has references to System.Runtime.CompilerServices.Unsafe and System.Memory -->
<Compile Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)'
and (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,10 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\CurrencyWrapper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\CustomQueryInterfaceMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\CustomQueryInterfaceResult.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\CustomTypeMarshallerAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\CustomTypeMarshallerDirection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\CustomTypeMarshallerFeatures.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\CustomTypeMarshallerKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\DefaultCharSetAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\DefaultDllImportSearchPathsAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\DefaultParameterValueAttribute.cs" />
Expand Down Expand Up @@ -852,8 +856,10 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalAsAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalDirectiveException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalUsingAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NativeLibrary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NativeMarshallingAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NativeMemory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\NFloat.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OptionalAttribute.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable enable

//
// Types in this file are used for generated p/invokes (docs/design/features/source-generator-pinvokes.md).
//
namespace System.Runtime.InteropServices
{
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Delegate)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
internal
#endif
sealed class NativeMarshallingAttribute : Attribute
{
public NativeMarshallingAttribute(Type nativeType)
{
NativeType = nativeType;
}

public Type NativeType { get; }
}

[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
internal
#endif
sealed class MarshalUsingAttribute : Attribute
{
public MarshalUsingAttribute()
{
CountElementName = string.Empty;
}

public MarshalUsingAttribute(Type nativeType)
: this()
{
NativeType = nativeType;
}

public Type? NativeType { get; }

public string CountElementName { get; set; }

public int ConstantElementCount { get; set; }

public int ElementIndirectionDepth { get; set; }

public const string ReturnsCountValue = "return-value";
}

/// <summary>
/// Attribute used to indicate that the type can be used to convert a value of the provided <see cref="ManagedType"/> to a native representation.
/// </summary>
Expand All @@ -63,12 +12,7 @@ public MarshalUsingAttribute(Type nativeType)
/// <seealso cref="LibraryImportAttribute"/>
/// </remarks>
[AttributeUsage(AttributeTargets.Struct)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
internal
#endif
sealed class CustomTypeMarshallerAttribute : Attribute
public sealed class CustomTypeMarshallerAttribute : Attribute
{
public CustomTypeMarshallerAttribute(Type managedType, CustomTypeMarshallerKind marshallerKind = CustomTypeMarshallerKind.Value)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ namespace System.Runtime.InteropServices
/// A direction of marshalling data into or out of the managed environment
/// </summary>
[Flags]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
internal
#endif
enum CustomTypeMarshallerDirection
public enum CustomTypeMarshallerDirection
{
/// <summary>
/// No marshalling direction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@ namespace System.Runtime.InteropServices
/// Optional features supported by custom type marshallers.
/// </summary>
[Flags]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
internal
#endif
enum CustomTypeMarshallerFeatures
public enum CustomTypeMarshallerFeatures
{
/// <summary>
/// No optional features supported
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ namespace System.Runtime.InteropServices
/// <remarks>
/// <seealso cref="LibraryImportAttribute"/>
/// </remarks>
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
internal
#endif
enum CustomTypeMarshallerKind
public enum CustomTypeMarshallerKind
{
/// <summary>
/// This custom type marshaller represents a single value.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Runtime.InteropServices
{
/// <summary>
/// Attribute used to provide a custom marshaller type or size information for marshalling.
/// </summary>
/// <remarks>
/// This attribute is recognized by the runtime-provided source generators for source-generated interop scenarios.
/// It is not used by the interop marshalling system at runtime.
/// <seealso cref="LibraryImportAttribute"/>
/// <seealso cref="CustomTypeMarshallerAttribute" />
/// </remarks>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
public sealed class MarshalUsingAttribute : Attribute
{
/// <summary>
/// Create a <see cref="MarshalUsingAttribute" /> that provides only size information.
/// </summary>
public MarshalUsingAttribute()
{
CountElementName = string.Empty;
}

/// <summary>
/// Create a <see cref="MarshalUsingAttribute" /> that provides a native marshalling type and optionally size information.
/// </summary>
/// <param name="nativeType">The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with <see cref="CustomTypeMarshallerAttribute" /></param>
public MarshalUsingAttribute(Type nativeType)
: this()
{
NativeType = nativeType;
}

/// <summary>
/// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with <see cref="CustomTypeMarshallerAttribute" />
/// </summary>
public Type? NativeType { get; }

/// <summary>
/// The name of the parameter that will provide the size of the collection when marshalling from unmanaged to managed, or <see cref="ReturnsCountValue" /> if the return value provides the size.
/// </summary>
/// <remarks>
/// Cannot be provided when <see cref="ConstantElementCount" /> is set.
/// </remarks>
public string CountElementName { get; set; }

/// <summary>
/// If a collection is constant size, the size of the collection when marshalling from unmanaged to managed.
/// </summary>
/// <remarks>
/// Cannot be provided when <see cref="CountElementName" /> is set.
/// </remarks>
public int ConstantElementCount { get; set; }

/// <summary>
/// What indirection depth this marshalling info is provided for.
/// </summary>
/// <remarks>
/// This value corresponds to how many pointer indirections would be required to get to the corresponding value from the native representation.
/// For example, this attribute is on a parameter of type <see cref="int" />[][], then an <see cref="ElementIndirectionDepth"/> of 0 means that the marshalling info applies to the managed type of <see cref="int" />[][],
/// an <see cref="ElementIndirectionDepth"/> of 1 applies to the managed type of <see cref="int" />[], and an <see cref="ElementIndirectionDepth"/> of 2 applies to the managed type of <see cref="int" />.
/// Only one <see cref="MarshalUsingAttribute" /> with a given <see cref="ElementIndirectionDepth" /> can be provided on a given parameter or return value.
/// </remarks>
public int ElementIndirectionDepth { get; set; }

/// <summary>
/// A constant string that represents the name of the return value for <see cref="CountElementName" />.
/// </summary>
public const string ReturnsCountValue = "return-value";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Runtime.InteropServices
{
/// <summary>
/// Attribute used to provide a default custom marshaller type for a given managed type.
/// </summary>
/// <remarks>
/// This attribute is recognized by the runtime-provided source generators for source-generated interop scenarios.
/// It is not used by the interop marshalling system at runtime.
/// <seealso cref="LibraryImportAttribute"/>
/// <seealso cref="CustomTypeMarshallerAttribute" />
/// </remarks>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Delegate)]
public sealed class NativeMarshallingAttribute : Attribute
{
/// <summary>
/// Create a <see cref="MarshalUsingAttribute" /> that provides a native marshalling type.
/// </summary>
/// <param name="nativeType">The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with <see cref="CustomTypeMarshallerAttribute" /></param>
public NativeMarshallingAttribute(Type nativeType)
{
NativeType = nativeType;
}

/// <summary>
/// The marshaller type used to convert the attributed type from managed to native code. This type must be attributed with <see cref="CustomTypeMarshallerAttribute" />
/// </summary>
public Type NativeType { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
<Nullable>enable</Nullable>
<RootNamespace>Microsoft.Interop</RootNamespace>
<RunAnalyzers>true</RunAnalyzers>
<DefineConstants>$(DefineConstants);LIBRARYIMPORT_GENERATOR_TEST</DefineConstants>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerKind.cs"
<Compile Include="$(LibrariesProjectRoot)System.Private.CoreLib\src\System\Runtime\InteropServices\CustomTypeMarshallerKind.cs"
Link="Common\System\Runtime\InteropServices\CustomTypeMarshallerKind.cs" />
<Compile Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerDirection.cs"
<Compile Include="$(LibrariesProjectRoot)System.Private.CoreLib\src\System\Runtime\InteropServices\CustomTypeMarshallerDirection.cs"
Link="Common\System\Runtime\InteropServices\CustomTypeMarshallerDirection.cs" />
<Compile Include="$(LibrariesProjectRoot)Common\src\System\Runtime\InteropServices\CustomTypeMarshallerFeatures.cs"
<Compile Include="$(LibrariesProjectRoot)System.Private.CoreLib\src\System\Runtime\InteropServices\CustomTypeMarshallerFeatures.cs"
Link="Common\System\Runtime\InteropServices\CustomTypeMarshallerFeatures.cs" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,41 @@ public enum CustomQueryInterfaceResult
NotHandled = 1,
Failed = 2,
}
[System.AttributeUsageAttribute(System.AttributeTargets.Struct)]
public sealed partial class CustomTypeMarshallerAttribute : System.Attribute
{
public CustomTypeMarshallerAttribute(System.Type managedType, System.Runtime.InteropServices.CustomTypeMarshallerKind marshallerKind = System.Runtime.InteropServices.CustomTypeMarshallerKind.Value) { }
public System.Type ManagedType { get { throw null; } }
public System.Runtime.InteropServices.CustomTypeMarshallerKind MarshallerKind { get { throw null; } }
public int BufferSize { get { throw null; } set { } }
public System.Runtime.InteropServices.CustomTypeMarshallerDirection Direction { get { throw null; } set { } }
public System.Runtime.InteropServices.CustomTypeMarshallerFeatures Features { get { throw null; } set { } }
public struct GenericPlaceholder
{
}
}
[System.FlagsAttribute]
public enum CustomTypeMarshallerDirection
{
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
None = 0,
In = 0x1,
Out = 0x2,
Ref = In | Out,
}
[System.FlagsAttribute]
public enum CustomTypeMarshallerFeatures
{
None = 0,
UnmanagedResources = 0x1,
CallerAllocatedBuffer = 0x2,
TwoStageMarshalling = 0x4
}
public enum CustomTypeMarshallerKind
{
Value,
LinearCollection
}
[System.AttributeUsageAttribute(System.AttributeTargets.Module, Inherited=false)]
public sealed partial class DefaultCharSetAttribute : System.Attribute
{
Expand Down Expand Up @@ -781,6 +816,17 @@ protected MarshalDirectiveException(System.Runtime.Serialization.SerializationIn
public MarshalDirectiveException(string? message) { }
public MarshalDirectiveException(string? message, System.Exception? inner) { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Parameter | System.AttributeTargets.ReturnValue, AllowMultiple = true)]
public sealed partial class MarshalUsingAttribute : System.Attribute
{
public MarshalUsingAttribute() { }
public MarshalUsingAttribute(System.Type nativeType) { }
public System.Type? NativeType { get { throw null; } }
public string CountElementName { get { throw null; } set { } }
public int ConstantElementCount { get { throw null; } set { } }
public int ElementIndirectionDepth { get { throw null; } set { } }
public const string ReturnsCountValue = "return-value";
}
public static partial class NativeLibrary
{
public static void Free(System.IntPtr handle) { }
Expand All @@ -793,6 +839,12 @@ public static void SetDllImportResolver(System.Reflection.Assembly assembly, Sys
public static bool TryLoad(string libraryPath, out System.IntPtr handle) { throw null; }
public static bool TryLoad(string libraryName, System.Reflection.Assembly assembly, System.Runtime.InteropServices.DllImportSearchPath? searchPath, out System.IntPtr handle) { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class | System.AttributeTargets.Enum | System.AttributeTargets.Delegate)]
public sealed partial class NativeMarshallingAttribute : System.Attribute
{
public NativeMarshallingAttribute(System.Type nativeType) { }
public System.Type NativeType { get { throw null; } }
}
public static unsafe partial class NativeMemory
{
[System.CLSCompliantAttribute(false)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<AssemblyName>Microsoft.Interop.Ancillary</AssemblyName>
<TargetFramework>$(NetCoreAppMinimum)</TargetFramework>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<RootNamespace>System.Runtime.InteropServices</RootNamespace>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Expand All @@ -11,10 +11,6 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/GeneratedMarshallingAttribute.cs" Link="GeneratedMarshallingAttribute.cs" />
<Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/CustomTypeMarshallerKind.cs" Link="CustomTypeMarshallerKind.cs" />
<Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/CustomTypeMarshallerDirection.cs" Link="CustomTypeMarshallerDirection.cs" />
<Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/CustomTypeMarshallerFeatures.cs" Link="CustomTypeMarshallerFeatures.cs" />
<Compile Include="$(LibrariesProjectRoot)Common/src/System/Runtime/InteropServices/ArrayMarshaller.cs" Link="ArrayMarshaller.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public static async Task<Compilation> CreateCompilation(SyntaxTree[] sources, Te
var referenceAssemblies = await GetReferenceAssemblies(targetFramework);

// [TODO] Can remove once ancillary logic is removed.
if (targetFramework is TestTargetFramework.Net6 or TestTargetFramework.Net)
if (targetFramework is TestTargetFramework.Net)
{
referenceAssemblies = referenceAssemblies.Add(GetAncillaryReference());
}
Expand Down Expand Up @@ -181,9 +181,9 @@ private static async Task<ImmutableArray<MetadataReference>> GetReferenceAssembl
/// <returns></returns>
internal static MetadataReference GetAncillaryReference()
{
// Include the assembly containing the new attribute and all of its references.
// [TODO] Remove once the attribute has been added to the BCL
var attrAssem = typeof(MarshalUsingAttribute).GetTypeInfo().Assembly;
// Include the assembly containing the new types we are considering exposing publicly
// but haven't put through API review.
var attrAssem = typeof(MarshalEx).GetTypeInfo().Assembly;
return MetadataReference.CreateFromFile(attrAssem.Location);
}

Expand Down