-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Add marshallers for GeneratedComInterface-based types #86177
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
jkoritzinsky
merged 16 commits into
dotnet:main
from
jkoritzinsky:interface-marshallers
May 20, 2023
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
efc7ffa
Allow NativeMarshalling on interfaces.
jkoritzinsky e18c8e9
Implement new marshaller types
jkoritzinsky c872e7d
Make sure we cast the returned COM interface pointer to the correct i…
jkoritzinsky 85725f5
Implement support in the source generators to automatically use the C…
jkoritzinsky 5ad9838
Fix ref leak.
jkoritzinsky 1198b18
Add some unit-test level tests for the interface marshalling logic.
jkoritzinsky a28d9a0
Add runtime tests for the interface marshallers, with some tests disa…
jkoritzinsky 4ac21c3
Fix compilation issues.
jkoritzinsky 3cdf629
Merge branch 'main' of github.com:dotnet/runtime into interface-marsh…
jkoritzinsky dedbecb
Enable tests that were disabled due to old Unwrap behavior
jkoritzinsky 06a0859
Use explicit type
jkoritzinsky 7093334
Set the TargetInterfaceIID with an initializer instead of a static co…
jkoritzinsky 8673d42
Add comments on behavior with non-GeneratedComInterface types
jkoritzinsky e8f238d
Update ApiCompat baseline and exclude ComImport types from the new ma…
jkoritzinsky c3ca8e1
Add test
jkoritzinsky 2d43ca9
Fix test build by removing unused parameter
jkoritzinsky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
...ropServices/gen/Microsoft.Interop.SourceGeneration/ComInterfaceMarshallingInfoProvider.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Microsoft.Interop | ||
{ | ||
/// <summary> | ||
/// This class supports generating marshalling info for types with the <c>System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute</c> attribute. | ||
/// </summary> | ||
public class ComInterfaceMarshallingInfoProvider : IMarshallingInfoAttributeParser | ||
{ | ||
private readonly Compilation _compilation; | ||
|
||
public ComInterfaceMarshallingInfoProvider(Compilation compilation) | ||
{ | ||
_compilation = compilation; | ||
} | ||
|
||
public bool CanParseAttributeType(INamedTypeSymbol attributeType) => attributeType.ToDisplayString() == TypeNames.GeneratedComInterfaceAttribute; | ||
|
||
public MarshallingInfo? ParseAttribute(AttributeData attributeData, ITypeSymbol type, int indirectionDepth, UseSiteAttributeProvider useSiteAttributes, GetMarshallingInfoCallback marshallingInfoCallback) | ||
{ | ||
return CreateComInterfaceMarshallingInfo(_compilation, type); | ||
} | ||
|
||
public static MarshallingInfo CreateComInterfaceMarshallingInfo( | ||
Compilation compilation, | ||
ITypeSymbol interfaceType) | ||
{ | ||
INamedTypeSymbol? comInterfaceMarshaller = compilation.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_Marshalling_ComInterfaceMarshaller_Metadata); | ||
if (comInterfaceMarshaller is null) | ||
return new MissingSupportMarshallingInfo(); | ||
|
||
comInterfaceMarshaller = comInterfaceMarshaller.Construct(interfaceType); | ||
|
||
if (ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(comInterfaceMarshaller)) | ||
{ | ||
if (ManualTypeMarshallingHelper.TryGetValueMarshallersFromEntryType(comInterfaceMarshaller, interfaceType, compilation, out CustomTypeMarshallers? marshallers)) | ||
{ | ||
return new NativeMarshallingAttributeInfo( | ||
EntryPointType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(comInterfaceMarshaller), | ||
Marshallers: marshallers.Value); | ||
} | ||
} | ||
|
||
return new MissingSupportMarshallingInfo(); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
....InteropServices/src/System/Runtime/InteropServices/Marshalling/ComInterfaceMarshaller.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// 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.Versioning; | ||
|
||
namespace System.Runtime.InteropServices.Marshalling | ||
{ | ||
/// <summary> | ||
/// COM interface marshaller using a StrategyBasedComWrappers instance | ||
/// </summary> | ||
/// <remarks> | ||
/// This marshaller will always pass the <see cref="CreateObjectFlags.Unwrap"/> flag | ||
/// to <see cref="ComWrappers.GetOrCreateObjectForComInstance(IntPtr, CreateObjectFlags)"/>. | ||
/// </remarks> | ||
[UnsupportedOSPlatform("android")] | ||
[UnsupportedOSPlatform("browser")] | ||
[UnsupportedOSPlatform("ios")] | ||
[UnsupportedOSPlatform("tvos")] | ||
[CLSCompliant(false)] | ||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder), MarshalMode.Default, typeof(ComInterfaceMarshaller<>))] | ||
public static unsafe class ComInterfaceMarshaller<T> | ||
{ | ||
private static readonly Guid? TargetInterfaceIID = StrategyBasedComWrappers.DefaultIUnknownInterfaceDetailsStrategy.GetIUnknownDerivedDetails(typeof(T).TypeHandle)?.Iid; | ||
|
||
public static void* ConvertToUnmanaged(T? managed) | ||
{ | ||
if (managed == null) | ||
{ | ||
return null; | ||
} | ||
if (!ComWrappers.TryGetComInstance(managed, out nint unknown)) | ||
{ | ||
unknown = StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateComInterfaceForObject(managed, CreateComInterfaceFlags.None); | ||
} | ||
jkoritzinsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return CastIUnknownToInterfaceType(unknown); | ||
} | ||
|
||
public static T? ConvertToManaged(void* unmanaged) | ||
{ | ||
if (unmanaged == null) | ||
{ | ||
return default; | ||
} | ||
return (T)StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateObjectForComInstance((nint)unmanaged, CreateObjectFlags.Unwrap); | ||
} | ||
|
||
internal static void* CastIUnknownToInterfaceType(nint unknown) | ||
{ | ||
if (TargetInterfaceIID is null) | ||
{ | ||
// If the managed type isn't a GeneratedComInterface-attributed type, we'll marshal to an IUnknown*. | ||
return (void*)unknown; | ||
jkoritzinsky marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
Guid iid = TargetInterfaceIID.Value; | ||
if (Marshal.QueryInterface(unknown, ref iid, out nint interfacePointer) != 0) | ||
{ | ||
Marshal.Release(unknown); | ||
throw new InvalidCastException($"Unable to cast the provided managed object to a COM interface with ID '{iid:B}'"); | ||
} | ||
Marshal.Release(unknown); | ||
return (void*)interfacePointer; | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
...opServices/src/System/Runtime/InteropServices/Marshalling/UniqueComInterfaceMarshaller.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// 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.Versioning; | ||
|
||
namespace System.Runtime.InteropServices.Marshalling | ||
{ | ||
/// <summary> | ||
/// COM interface marshaller using a StrategyBasedComWrappers instance | ||
/// that will only create unique native object wrappers (RCW). | ||
/// </summary> | ||
/// <remarks> | ||
/// This marshaller will always pass the <see cref="CreateObjectFlags.Unwrap"/> and <see cref="CreateObjectFlags.UniqueInstance"/> flags | ||
/// to <see cref="ComWrappers.GetOrCreateObjectForComInstance(IntPtr, CreateObjectFlags)"/>. | ||
/// </remarks> | ||
[UnsupportedOSPlatform("android")] | ||
[UnsupportedOSPlatform("browser")] | ||
[UnsupportedOSPlatform("ios")] | ||
[UnsupportedOSPlatform("tvos")] | ||
[CLSCompliant(false)] | ||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder), MarshalMode.Default, typeof(UniqueComInterfaceMarshaller<>))] | ||
public static unsafe class UniqueComInterfaceMarshaller<T> | ||
{ | ||
public static void* ConvertToUnmanaged(T? managed) | ||
{ | ||
if (managed == null) | ||
{ | ||
return null; | ||
} | ||
if (!ComWrappers.TryGetComInstance(managed, out nint unknown)) | ||
{ | ||
unknown = StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateComInterfaceForObject(managed, CreateComInterfaceFlags.None); | ||
} | ||
return ComInterfaceMarshaller<T>.CastIUnknownToInterfaceType(unknown); | ||
} | ||
|
||
public static T? ConvertToManaged(void* unmanaged) | ||
{ | ||
if (unmanaged == null) | ||
{ | ||
return default; | ||
} | ||
return (T)StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateObjectForComInstance((nint)unmanaged, CreateObjectFlags.Unwrap | CreateObjectFlags.UniqueInstance); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.