Skip to content

Commit

Permalink
Expose the custom type marshalling types for source-generated interop. (
Browse files Browse the repository at this point in the history
#67052)

Co-authored-by: Elinor Fung <[email protected]>
  • Loading branch information
jkoritzinsky and elinor-fung authored Mar 25, 2022
1 parent 9047692 commit 32320b1
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 98 deletions.
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

0 comments on commit 32320b1

Please sign in to comment.