Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Runtime.InteropServices;
using AsmResolver;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using WindowsRuntime.InteropGenerator.Errors;
using WindowsRuntime.InteropGenerator.Factories;
using WindowsRuntime.InteropGenerator.Generation;
using WindowsRuntime.InteropGenerator.References;

namespace WindowsRuntime.InteropGenerator.Builders;

/// <summary>
/// A builder for the dynamic type map entries for custom-mapped types.
/// </summary>
internal static partial class DynamicCustomMappedTypeMapEntriesBuilder
{
/// <summary>
/// Defines all assembly attributes for dynamic custom-mapped type map entries.
/// </summary>
/// <param name="args">The arguments for this invocation.</param>
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The interop module being built.</param>
public static void AssemblyAttributes(
InteropGeneratorArgs args,
InteropReferences interopReferences,
ModuleDefinition module)
{
ManagedOnlyTypeOrInterface(
args: args,
windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.IBindableIterable",
microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.IBindableIterable",
target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.Collections"u8, "IEnumerable"u8).ToReferenceTypeSignature(),
trimTarget: interopReferences.IEnumerable.ToReferenceTypeSignature(),
interopReferences: interopReferences,
module: module);

ManagedOnlyTypeOrInterface(
args: args,
windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.IBindableIterator",
microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.IBindableIterator",
target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.Collections"u8, "IEnumerator"u8).ToReferenceTypeSignature(),
trimTarget: interopReferences.IEnumerator.ToReferenceTypeSignature(),
interopReferences: interopReferences,
module: module);

ManagedOnlyTypeOrInterface(
args: args,
windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.IBindableVector",
microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.IBindableVector",
target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.Collections"u8, "IList"u8).ToReferenceTypeSignature(),
trimTarget: interopReferences.IList.ToReferenceTypeSignature(),
interopReferences: interopReferences,
module: module);

ManagedOnlyTypeOrInterface(
args: args,
windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs",
microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs",
target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.Collections.Specialized"u8, "NotifyCollectionChangedEventArgs"u8).ToReferenceTypeSignature(),
trimTarget: interopReferences.NotifyCollectionChangedEventArgs.ToReferenceTypeSignature(),
interopReferences: interopReferences,
module: module);

ManagedOnlyTypeOrInterface(
args: args,
windowsUIXamlTypeName: "Windows.UI.Xaml.Data.PropertyChangedEventArgs",
microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Data.PropertyChangedEventArgs",
target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.ComponentModel"u8, "PropertyChangedEventArgs"u8).ToReferenceTypeSignature(),
trimTarget: interopReferences.PropertyChangedEventArgs.ToReferenceTypeSignature(),
interopReferences: interopReferences,
module: module);

WindowsRuntimeExposedType(
args: args,
windowsUIXamlTypeName: "Windows.Foundation.IReference<Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler>",
microsoftUIXamlTypeName: "Windows.Foundation.IReference<Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventHandler>",
trimTarget: interopReferences.NotifyCollectionChangedEventHandler.ToReferenceTypeSignature(),
interopReferences: interopReferences,
module: module);

WindowsRuntimeExposedType(
args: args,
windowsUIXamlTypeName: "Windows.Foundation.IReference<Windows.UI.Xaml.Data.PropertyChangedEventHandler>",
microsoftUIXamlTypeName: "Windows.Foundation.IReference<Microsoft.UI.Xaml.Data.PropertyChangedEventHandler>",
trimTarget: interopReferences.PropertyChangedEventHandler.ToReferenceTypeSignature(),
interopReferences: interopReferences,
module: module);

WindowsRuntimeExposedType(
args: args,
windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.IBindableVectorView",
microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.IBindableVectorView",
trimTarget: interopReferences.BindableIReadOnlyListAdapter.ToReferenceTypeSignature(),
interopReferences: interopReferences,
module: module);
}

/// <summary>
/// Creates a new custom attribute value for <see cref="TypeMapAttribute{TTypeMapGroup}"/> for a given custom-mapped type that is never marshalled or instantiated.
/// </summary>
/// <param name="args">The arguments for this invocation.</param>
/// <param name="windowsUIXamlTypeName">The runtime class name for <c>Windows.UI.Xaml</c>.</param>
/// <param name="microsoftUIXamlTypeName">The runtime class name for <c>Microsoft.UI.Xaml</c>.</param>
/// <param name="target"><inheritdoc cref="TypeMapAttribute{TTypeMapGroup}.TypeMapAttribute(string, Type, Type)" path="/param[@name='target']/node()"/></param>
/// <param name="trimTarget"><inheritdoc cref="TypeMapAttribute{TTypeMapGroup}.TypeMapAttribute(string, Type, Type)" path="/param[@name='trimTarget']/node()"/></param>
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The module that the attribute will be used from.</param>
private static void ManagedOnlyTypeOrInterface(
InteropGeneratorArgs args,
string windowsUIXamlTypeName,
string microsoftUIXamlTypeName,
TypeSignature target,
TypeSignature trimTarget,
InteropReferences interopReferences,
ModuleDefinition module)
{
module.Assembly!.CustomAttributes.Add(InteropCustomAttributeFactory.TypeMapWindowsRuntimeComWrappersTypeMapGroup(
value: args.UseWindowsUIXamlProjections ? windowsUIXamlTypeName : microsoftUIXamlTypeName,
target: target,
trimTarget: trimTarget,
interopReferences: interopReferences,
module: module));
}

/// <summary>
/// Creates a new custom attribute value for <see cref="TypeMapAttribute{TTypeMapGroup}"/> for a given custom-mapped type that can be marshalled to native.
/// </summary>
/// <param name="args">The arguments for this invocation.</param>
/// <param name="windowsUIXamlTypeName">The runtime class name for <c>Windows.UI.Xaml</c>.</param>
/// <param name="microsoftUIXamlTypeName">The runtime class name for <c>Microsoft.UI.Xaml</c>.</param>
/// <param name="trimTarget"><inheritdoc cref="TypeMapAttribute{TTypeMapGroup}.TypeMapAttribute(string, Type, Type)" path="/param[@name='trimTarget']/node()"/></param>
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The module that the attribute will be used from.</param>
private static void WindowsRuntimeExposedType(
InteropGeneratorArgs args,
string windowsUIXamlTypeName,
string microsoftUIXamlTypeName,
TypeSignature trimTarget,
InteropReferences interopReferences,
ModuleDefinition module)
{
string runtimeClassName = args.UseWindowsUIXamlProjections ? windowsUIXamlTypeName : microsoftUIXamlTypeName;

// Retrieve the '[ComWrappersMarshaller]' type from 'WinRT.Runtime.dll', which always follows this naming convention
TypeReference comWrappersMarshallerTypeReference = interopReferences.WindowsRuntimeModule.CreateTypeReference(
ns: InteropUtf8NameFactory.TypeNamespace(trimTarget),
name: (Utf8String)$"{trimTarget.Name}ComWrappersMarshallerAttribute");

// The '[ComWrappersMarshaller]' type should always exist for all custom-mapped types, throw if it doesn't
if (comWrappersMarshallerTypeReference.Import(module).Resolve() is not TypeDefinition comWrappersMarshallerType)
{
throw WellKnownInteropExceptions.CustomMappedTypeComWrappersMarshallerAttributeTypeResolveError(comWrappersMarshallerTypeReference);
}

// Because these types can be instantiated and marshalled to native, but their runtime class name changes between 'Windows.UI.Xaml' and
// 'Microsoft.UI.Xaml', we also need to generate a proxy type for them, so that we can annotate it with '[WindowsRuntimeClassName]' with
// the correct runtime class name for the configuration actually being used at runtime by the current application or published library.
InteropTypeDefinitionBuilder.Proxy(
ns: InteropUtf8NameFactory.TypeNamespace(trimTarget),
name: trimTarget.Name!,
runtimeClassName: runtimeClassName,
comWrappersMarshallerAttributeType: comWrappersMarshallerType,
interopReferences: interopReferences,
module: module,
out TypeDefinition proxyType);

module.Assembly!.CustomAttributes.Add(InteropCustomAttributeFactory.TypeMapWindowsRuntimeComWrappersTypeMapGroup(
value: args.UseWindowsUIXamlProjections ? windowsUIXamlTypeName : microsoftUIXamlTypeName,
target: proxyType.ToTypeSignature(),
trimTarget: trimTarget,
interopReferences: interopReferences,
module: module));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public static void InterfaceEntriesImpl(
TypeReference typeReference = interopReferences.WindowsRuntimeModule.CreateTypeReference($"ABI.{typeSignature.Namespace}", $"{typeSignature.Name}Impl");
MemberReference get_VtableMethod = typeReference.CreateMemberReference("get_Vtable"u8, MethodSignature.CreateStatic(interopReferences.CorLibTypeFactory.IntPtr));

// For custom mapped types, the IID is in 'WellKnownInterfaceIIDs' in 'WinRT.Runtime.dll'
// For custom-mapped types, the IID is in 'WellKnownInterfaceIIDs' in 'WinRT.Runtime.dll'
string get_IIDMethodName = $"get_IID_{typeSignature.FullName.Replace('.', '_')}";
TypeSignature get_IIDMethodReturnType = WellKnownTypeSignatureFactory.InGuid(interopReferences);
MemberReference get_IIDMethod = interopReferences.WellKnownInterfaceIIDs.CreateMemberReference(get_IIDMethodName, MethodSignature.CreateStatic(get_IIDMethodReturnType));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private static void IID(
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The interop module being built.</param>
/// <param name="nativeObjectType">The resulting native object type.</param>
public static void NativeObject(
private static void NativeObject(
TypeSignature typeSignature,
TypeSignature nativeObjectBaseType,
InteropReferences interopReferences,
Expand Down Expand Up @@ -98,7 +98,7 @@ public static void NativeObject(
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The interop module being built.</param>
/// <param name="callbackType">The resulting callback type.</param>
public static void ComWrappersCallback(
private static void ComWrappersCallback(
string runtimeClassName,
TypeSignature typeSignature,
TypeDefinition nativeObjectType,
Expand Down Expand Up @@ -200,7 +200,7 @@ public static void ComWrappersCallback(
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The module that will contain the type being created.</param>
/// <param name="marshallerType">The resulting marshaller type.</param>
public static void ComWrappersMarshallerAttribute(
private static void ComWrappersMarshallerAttribute(
TypeSignature typeSignature,
TypeDefinition nativeObjectType,
MethodDefinition get_IidMethod,
Expand Down Expand Up @@ -265,7 +265,7 @@ public static void ComWrappersMarshallerAttribute(
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The module that will contain the type being created.</param>
/// <param name="marshallerType">The resulting marshaller type.</param>
public static void Marshaller(
private static void Marshaller(
TypeSignature typeSignature,
TypeDefinition interfaceComWrappersCallbackType,
MethodDefinition get_IidMethod,
Expand Down Expand Up @@ -349,7 +349,7 @@ public static void Marshaller(
/// <param name="module">The interop module being built.</param>
/// <param name="implType">The resulting implementation type.</param>
/// <param name="vtableMethods">The set of implementation methods for the implementation type.</param>
public static void Impl(
private static void Impl(
[ConstantExpected] ComInterfaceType interfaceType,
Utf8String ns,
Utf8String name,
Expand Down Expand Up @@ -594,7 +594,7 @@ public static void Proxy(
value: runtimeClassName))));

// Add the generated marshaller attribute
marshallerType.CustomAttributes.Add(new CustomAttribute(comWrappersMarshallerAttributeType.GetConstructor()!));
marshallerType.CustomAttributes.Add(new CustomAttribute(comWrappersMarshallerAttributeType.GetConstructor()!.Import(module)));
}

/// <summary>
Expand All @@ -609,7 +609,7 @@ public static void Proxy(
/// <param name="interfaceTypeMapProxyType">The IDIC proxy type for <see cref="TypeMapAssociationAttribute{TTypeMapGroup}.TypeMapAssociationAttribute(Type, Type)"/>.</param>
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The module that will contain the type being created.</param>
public static void TypeMapAttributes(
private static void TypeMapAttributes(
string? runtimeClassName,
[NotNullIfNotNull(nameof(runtimeClassName))] TypeSignature? externalTypeMapTargetType,
[NotNullIfNotNull(nameof(runtimeClassName))] TypeSignature? externalTypeMapTrimTargetType,
Expand Down
17 changes: 17 additions & 0 deletions src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;

namespace WindowsRuntime.InteropGenerator.Errors;
Expand Down Expand Up @@ -386,6 +387,22 @@ public static Exception DynamicImplementationDetailTypeCodeGenerationError(Excep
return Exception(43, $"Failed to generate marshalling code for some dynamic implementation detail type.", exception);
}

/// <summary>
/// Failed to generate marshalling code for a dynamic implementation detail type.
/// </summary>
public static Exception DynamicDynamicCustomMappedTypeMapEntriesCodeGenerationError(Exception exception)
{
return Exception(44, $"Failed to generate type map entries for some dynamic custom-mapped types.", exception);
}

/// <summary>
/// Failed to resolve the associated <c>ComWrappersMarshallerAttribute</c> type for a custom-mapped type.
/// </summary>
public static Exception CustomMappedTypeComWrappersMarshallerAttributeTypeResolveError(TypeReference type)
{
return Exception(45, $"Failed to resolve the associated 'ComWrappersMarshallerAttribute' type for the custom-mapped type '{type}'.");
}

/// <summary>
/// Creates a new exception with the specified id and message.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ private static void DiscoverGenericTypeInstantiations(
TypeDefinition typeDefinition = typeSignature.Resolve()!;

// Gather all known delegate types. We want to gather all projected delegate types, plus any
// custom mapped ones (e.g. 'EventHandler<TEventArgs>' and 'EventHandler<TSender, TEventArgs>').
// custom-mapped ones (e.g. 'EventHandler<TEventArgs>' and 'EventHandler<TSender, TEventArgs>').
// We need to check whether the type is a projected Windows Runtime type from the resolved type
// definition, and not from the generic type definition we can retrieve from the type signature.
// If we did the latter, the resulting type definition would not include any custom attributes.
Expand Down
29 changes: 29 additions & 0 deletions src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ private static void Emit(InteropGeneratorArgs args, InteropGeneratorDiscoverySta

args.Token.ThrowIfCancellationRequested();

// Add all dynamic type map entries for custom-mapped types
DefineDynamicCustomMappedTypeMapEntries(args, interopReferences, module);

args.Token.ThrowIfCancellationRequested();

// Add all '[IgnoreAccessChecksTo]' attributes
DefineIgnoreAccessChecksToAttributes(discoveryState, interopDefinitions, module);

Expand Down Expand Up @@ -1713,6 +1718,30 @@ private static void DefineDynamicImplementationDetailTypes(InteropDefinitions in
}
}

/// <summary>
/// Defines the dynamic type map entries for custom-mapped types.
/// </summary>
/// <param name="args"><inheritdoc cref="Emit" path="/param[@name='args']/node()"/></param>
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="module">The interop module being built.</param>
private static void DefineDynamicCustomMappedTypeMapEntries(
InteropGeneratorArgs args,
InteropReferences interopReferences,
ModuleDefinition module)
{
try
{
DynamicCustomMappedTypeMapEntriesBuilder.AssemblyAttributes(
args: args,
interopReferences: interopReferences,
module: module);
}
catch (Exception e) when (!e.IsWellKnown)
{
throw WellKnownInteropExceptions.DynamicDynamicCustomMappedTypeMapEntriesCodeGenerationError(e);
}
}

/// <summary>
/// Defines the <c>[IgnoreAccessChecksTo]</c> attribute, and applies it to the assembly for each input reference.
/// </summary>
Expand Down
Loading
Loading