diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index fa27beecd..0b1b74009 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -8,8 +8,9 @@ using AsmResolver.PE.DotNet.Cil; using AsmResolver.PE.DotNet.Metadata.Tables; using WindowsRuntime.InteropGenerator.Factories; -using WindowsRuntime.InteropGenerator.References; +using WindowsRuntime.InteropGenerator.Generation; using WindowsRuntime.InteropGenerator.Helpers; +using WindowsRuntime.InteropGenerator.References; using static AsmResolver.PE.DotNet.Cil.CilOpCodes; namespace WindowsRuntime.InteropGenerator.Builders; @@ -71,19 +72,28 @@ public static void IIDs( /// The for the type. /// The instance to use. /// The instance to use. + /// The emit state for this invocation. /// The interop module being built. /// The resulting implementation type. public static void ImplType( GenericInstanceTypeSignature delegateType, InteropDefinitions interopDefinitions, InteropReferences interopReferences, + InteropGeneratorEmitState emitState, ModuleDefinition module, out TypeDefinition implType) { + MemberReference delegateInvokeMethod = interopReferences.DelegateInvoke(delegateType, module); + + // Prepare the sender and arguments types. This path is only ever reached for valid + // generic Windows Runtime delegate types, and they all have exactly two type arguments. + TypeSignature senderType = ((MethodSignature)delegateInvokeMethod.Signature!).ParameterTypes[0]; + TypeSignature argsType = ((MethodSignature)delegateInvokeMethod.Signature!).ParameterTypes[1]; + // Define the 'Invoke' method as follows: // // [UnmanagedCallersOnly(CallConvs = [typeof(CallConvMemberFunction)])] - // private static int Invoke(void* thisPtr, void* sender, void* e) + // private static int Invoke(void* thisPtr, sender, e) MethodDefinition invokeMethod = new( name: "Invoke"u8, attributes: MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, @@ -91,8 +101,8 @@ public static void ImplType( returnType: module.CorLibTypeFactory.Int32, parameterTypes: [ module.CorLibTypeFactory.Void.MakePointerType(), - module.CorLibTypeFactory.Void.MakePointerType(), - module.CorLibTypeFactory.Void.MakePointerType()])) + senderType.GetAbiType(interopReferences).Import(module), + argsType.GetAbiType(interopReferences).Import(module)])) { CustomAttributes = { InteropCustomAttributeFactory.UnmanagedCallersOnly(interopReferences, module) } }; @@ -101,6 +111,8 @@ public static void ImplType( CilInstruction ldloc_0_returnHResult = new(Ldloc_0); CilInstruction ldarg_0_tryStart = new(Ldarg_0); CilInstruction call_catchStartMarshalException = new(Call, interopReferences.RestrictedErrorInfoExceptionMarshallerConvertToUnmanaged.Import(module)); + CilInstruction nop_parameter1Rewrite = new(Nop); + CilInstruction nop_parameter2Rewrite = new(Nop); // Create a method body for the 'Invoke' method invokeMethod.CilMethodBody = new CilMethodBody() @@ -113,11 +125,9 @@ public static void ImplType( // '.try' code { ldarg_0_tryStart }, { Call, interopReferences.ComInterfaceDispatchGetInstance.MakeGenericInstanceMethod(delegateType).Import(module) }, - { Ldarg_1 }, - { Call, interopReferences.WindowsRuntimeObjectMarshallerConvertToManaged.Import(module) }, - { Ldarg_2 }, - { Call, interopReferences.WindowsRuntimeObjectMarshallerConvertToManaged.Import(module) }, - { Callvirt, interopReferences.DelegateInvoke(delegateType, module).Import(module) }, + { nop_parameter1Rewrite }, + { nop_parameter2Rewrite }, + { Callvirt, delegateInvokeMethod.Import(module) }, { Ldc_I4_0 }, { Stloc_0 }, { Leave_S, ldloc_0_returnHResult.CreateLabel() }, @@ -145,6 +155,19 @@ public static void ImplType( } }; + // Track rewriting the two parameters for this method + emitState.TrackManagedParameterMethodRewrite( + paraneterType: senderType, + method: invokeMethod, + marker: nop_parameter1Rewrite, + parameterIndex: 1); + + emitState.TrackManagedParameterMethodRewrite( + paraneterType: argsType, + method: invokeMethod, + marker: nop_parameter2Rewrite, + parameterIndex: 2); + Impl( interfaceType: ComInterfaceType.InterfaceIsIUnknown, ns: InteropUtf8NameFactory.TypeNamespace(delegateType), @@ -387,6 +410,12 @@ public static void NativeDelegateType( ModuleDefinition module, out TypeDefinition nativeDelegateType) { + MemberReference delegateInvokeMethod = interopReferences.DelegateInvoke(delegateType, module); + + // Prepare the sender and arguments types (same as for the 'Impl' type above) + TypeSignature senderType = ((MethodSignature)delegateInvokeMethod.Signature!).ParameterTypes[0]; + TypeSignature argsType = ((MethodSignature)delegateInvokeMethod.Signature!).ParameterTypes[1]; + // We're declaring an 'internal static class' type nativeDelegateType = new( ns: InteropUtf8NameFactory.TypeNamespace(delegateType), @@ -396,9 +425,6 @@ public static void NativeDelegateType( module.TopLevelTypes.Add(nativeDelegateType); - // Construct the 'Invoke' method on the delegate type, so we can get the constructed parameter types - MethodSignature invokeSignature = delegateType.Import(module).Resolve()!.GetMethod("Invoke"u8).Signature!.InstantiateGenericTypes(GenericContext.FromType(delegateType)); - // Define the 'Invoke' method as follows: // // public static void Invoke(WindowsRuntimeObjectReference objectReference, arg0, arg1) @@ -409,8 +435,8 @@ public static void NativeDelegateType( returnType: module.CorLibTypeFactory.Void, parameterTypes: [ interopReferences.WindowsRuntimeObjectReference.ToReferenceTypeSignature().Import(module), - invokeSignature.ParameterTypes[0].Import(module), - invokeSignature.ParameterTypes[1].Import(module)])) + senderType.Import(module), + argsType.Import(module)])) { CilMethodBody = new CilMethodBody() }; nativeDelegateType.Methods.Add(invokeMethod); @@ -626,6 +652,7 @@ public static void ComWrappersMarshallerAttribute( /// The 'IID' get method for the 'IDelegate' interface. /// The resulting 'IID' get method for the boxed 'IDelegate' interface. /// The instance to use. + /// The emit state for this invocation. /// The module that will contain the type being created. /// The resulting marshaller type. public static void Marshaller( @@ -634,6 +661,7 @@ public static void Marshaller( MethodDefinition get_IidMethod, MethodDefinition get_ReferenceIidMethod, InteropReferences interopReferences, + InteropGeneratorEmitState emitState, ModuleDefinition module, out TypeDefinition marshallerType) { @@ -744,6 +772,9 @@ public static void Marshaller( }; marshallerType.Methods.Add(unboxToUnmanagedMethod); + + // Track the type (it may be needed to marshal parameters or return values) + emitState.TrackTypeDefinition(marshallerType, delegateType, "Marshaller"); } /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs index daee341c9..18843baa7 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs @@ -227,32 +227,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IAsyncActionWithProgress<TProgress> interface. - /// - /// The for the async action type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature actionType, - TypeDefinition operationComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: actionType, - interfaceComWrappersCallbackType: operationComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - } - /// /// Creates a new type definition for the interface implementation of some IAsyncActionWithProgress<TProgress> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs index e45035665..30c6749f1 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs @@ -180,32 +180,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IAsyncOperation1<TResult> interface. - /// - /// The for the async operation type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature operationType, - TypeDefinition operationComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: operationType, - interfaceComWrappersCallbackType: operationComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - } - /// /// Creates a new type definition for the interface implementation of some IAsyncOperation1<TResult> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs index 0d856babb..214ced000 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs @@ -222,32 +222,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IAsyncOperationWithProgress<TResult, TProgress> interface. - /// - /// The for the async operation type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature operationType, - TypeDefinition operationComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: operationType, - interfaceComWrappersCallbackType: operationComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - } - /// /// Creates a new type definition for the interface implementation of some IAsyncOperationWithProgress<TResult, TProgress> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs index 6f05e21aa..36b170243 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs @@ -729,37 +729,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IMap<K, V> interface. - /// - /// The for the type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The emit state for this invocation. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature dictionaryType, - TypeDefinition dictionaryComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - InteropGeneratorEmitState emitState, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: dictionaryType, - interfaceComWrappersCallbackType: dictionaryComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - - // Track the type (it may be needed to marshal parameters or return values) - emitState.TrackTypeDefinition(marshallerType, dictionaryType, "Marshaller"); - } - /// /// Creates a new type definition for the interface implementation of some IMap<K, V> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs index 8e8c7750f..fbb78f40d 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs @@ -342,37 +342,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IIterable<T> interface. - /// - /// The for the type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The emit state for this invocation. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature enumerableType, - TypeDefinition enumerableComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - InteropGeneratorEmitState emitState, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: enumerableType, - interfaceComWrappersCallbackType: enumerableComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - - // Track the type (it may be needed to marshal parameters or return values) - emitState.TrackTypeDefinition(marshallerType, enumerableType, "Marshaller"); - } - /// /// Creates a new type definition for the interface implementation of some IIterable<T> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs index b3865e57b..9eb83a639 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs @@ -256,37 +256,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IIterator<T> interface. - /// - /// The for the type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The emit state for this invocation. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature enumeratorType, - TypeDefinition enumeratorComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - InteropGeneratorEmitState emitState, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: enumeratorType, - interfaceComWrappersCallbackType: enumeratorComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - - // Track the type (it's needed by 'IEnumerable') - emitState.TrackTypeDefinition(marshallerType, enumeratorType, "Marshaller"); - } - /// /// Creates a new type definition for the interface implementation of some IIterator<T> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs index 82b89cfad..f4a5e8999 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs @@ -657,37 +657,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IVector<T> interface. - /// - /// The for the type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The emit state for this invocation. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature listType, - TypeDefinition listComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - InteropGeneratorEmitState emitState, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: listType, - interfaceComWrappersCallbackType: listComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - - // Track the type (it may be needed to marshal parameters or return values) - emitState.TrackTypeDefinition(marshallerType, listType, "Marshaller"); - } - /// /// Creates a new type definition for the interface implementation of some IVector<T> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs index ddce82f70..9bb8629da 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs @@ -177,37 +177,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IMapChangedEventArgs<K> interface. - /// - /// The for the args type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The emit state for this invocation. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature argsType, - TypeDefinition argsComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - InteropGeneratorEmitState emitState, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: argsType, - interfaceComWrappersCallbackType: argsComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - - // Track the type (it's needed by 'IEnumerable') - emitState.TrackTypeDefinition(marshallerType, argsType, "Marshaller"); - } - /// /// Creates a new type definition for the interface implementation of some IMapChangedEventArgs<K> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs index c707f8ec2..bb195eaa7 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs @@ -300,32 +300,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IObservableMap<K, V> interface. - /// - /// The for the map type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature mapType, - TypeDefinition mapComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: mapType, - interfaceComWrappersCallbackType: mapComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - } - /// /// Creates a new type definition for the interface implementation of some IObservableMap<K, V> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs index d70160642..efce554ba 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs @@ -295,32 +295,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IObservableVector<T> interface. - /// - /// The for the vector type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature vectorType, - TypeDefinition vectorComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: vectorType, - interfaceComWrappersCallbackType: vectorComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - } - /// /// Creates a new type definition for the interface implementation of some IObservableVector<T> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs index b99efcaac..179251ee8 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs @@ -384,37 +384,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IMapView<K, V> interface. - /// - /// The for the type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The emit state for this invocation. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature readOnlyDictionaryType, - TypeDefinition readOnlyDictionaryComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - InteropGeneratorEmitState emitState, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: readOnlyDictionaryType, - interfaceComWrappersCallbackType: readOnlyDictionaryComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - - // Track the type (it may be needed to marshal parameters or return values) - emitState.TrackTypeDefinition(marshallerType, readOnlyDictionaryType, "Marshaller"); - } - /// /// Creates a new type definition for the interface implementation of some IMapView<K, V> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs index 1a0df72a0..7e78946a9 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs @@ -269,37 +269,6 @@ public static void ComWrappersMarshallerAttribute( out marshallerType); } - /// - /// Creates a new type definition for the marshaller of some IVectorView<T> interface. - /// - /// The for the type. - /// The instance returned by . - /// The 'IID' get method for . - /// The instance to use. - /// The emit state for this invocation. - /// The module that will contain the type being created. - /// The resulting marshaller type. - public static void Marshaller( - GenericInstanceTypeSignature readOnlyListType, - TypeDefinition readOnlyListComWrappersCallbackType, - MethodDefinition get_IidMethod, - InteropReferences interopReferences, - InteropGeneratorEmitState emitState, - ModuleDefinition module, - out TypeDefinition marshallerType) - { - InteropTypeDefinitionBuilder.Marshaller( - typeSignature: readOnlyListType, - interfaceComWrappersCallbackType: readOnlyListComWrappersCallbackType, - get_IidMethod: get_IidMethod, - interopReferences: interopReferences, - module: module, - out marshallerType); - - // Track the type (it may be needed to marshal parameters or return values) - emitState.TrackTypeDefinition(marshallerType, readOnlyListType, "Marshaller"); - } - /// /// Creates a new type definition for the interface implementation of some IVectorView<T> interface. /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs index 8d6f17008..f132b0201 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs @@ -136,9 +136,6 @@ public static void Marshaller( module.TopLevelTypes.Add(marshallerType); - // Track the type (it may be needed to marshal parameters or return values) - emitState.TrackTypeDefinition(marshallerType, keyValuePairType, "Marshaller"); - // Prepare the external types we need in the implemented methods TypeSignature typeSignature2 = keyValuePairType.Import(module); TypeSignature windowsRuntimeObjectReferenceValueType = interopReferences.WindowsRuntimeObjectReferenceValue.Import(module).ToValueTypeSignature(); @@ -214,6 +211,9 @@ public static void Marshaller( }; marshallerType.Methods.Add(convertToManagedMethod); + + // Track the type (it may be needed to marshal parameters or return values) + emitState.TrackTypeDefinition(marshallerType, keyValuePairType, "Marshaller"); } /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs index d6ed1fea0..bfb3127f7 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs @@ -11,6 +11,7 @@ using AsmResolver.PE.DotNet.Cil; using AsmResolver.PE.DotNet.Metadata.Tables; using WindowsRuntime.InteropGenerator.Factories; +using WindowsRuntime.InteropGenerator.Generation; using WindowsRuntime.InteropGenerator.Helpers; using WindowsRuntime.InteropGenerator.References; using static AsmResolver.PE.DotNet.Cil.CilOpCodes; @@ -290,13 +291,15 @@ private static void ComWrappersMarshallerAttribute( /// The instance returned by . /// The 'IID' get method for . /// The instance to use. + /// The emit state for this invocation. /// The module that will contain the type being created. /// The resulting marshaller type. - private static void Marshaller( + public static void Marshaller( TypeSignature typeSignature, TypeDefinition interfaceComWrappersCallbackType, MethodDefinition get_IidMethod, InteropReferences interopReferences, + InteropGeneratorEmitState emitState, ModuleDefinition module, out TypeDefinition marshallerType) { @@ -363,6 +366,9 @@ private static void Marshaller( }; marshallerType.Methods.Add(convertToManagedMethod); + + // Track the type (it may be needed to marshal parameters or return values) + emitState.TrackTypeDefinition(marshallerType, typeSignature, "Marshaller"); } /// diff --git a/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.Generics.cs b/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.Generics.cs index 19b21da16..6b8294d01 100644 --- a/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.Generics.cs +++ b/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.Generics.cs @@ -302,6 +302,9 @@ private static void TryTrackWindowsRuntimeGenericInterfaceTypeInstance( // Same handling as above for 'MapChangedEventHandler' types discoveryState.TrackGenericDelegateType(interopReferences.MapChangedEventHandler2.MakeGenericReferenceType([.. typeSignature.TypeArguments])); + + // Also manually track the args type for 'MapChangedEventHandler' + discoveryState.TrackIMapChangedEventArgs1Type(interopReferences.IMapChangedEventArgs1.MakeGenericReferenceType(typeSignature.TypeArguments[1])); } else if (SignatureComparer.IgnoreVersion.Equals(typeSignature.GenericType, interopReferences.IMapChangedEventArgs1)) { diff --git a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs index 50d273efe..b7a32c0d8 100644 --- a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs +++ b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs @@ -573,6 +573,30 @@ public static WellKnownInteropWarning WindowsRuntimeClassTypeNotResolvedWarning( return Warning(66, $"Failed to resolve the base type '{baseType}' for Windows Runtime class type '{classType}': runtime casts to the base type will not work if the type is trimmed."); } + /// + /// A parameter index was not valid in a generated interop method. + /// + public static WellKnownInteropException MethodRewriteSourceLocalTypeMismatchError(TypeSignature localType, TypeSignature returnType, MethodDefinition method) + { + return Exception(67, $"Local variable of type '{localType}' cannot be used to marshal a value of type '{returnType}' in generated interop method '{method}'."); + } + + /// + /// The type of a local was not valid in a generated interop method. + /// + public static WellKnownInteropException MethodRewriteParameterIndexNotValidError(int parameterIndex, MethodDefinition method) + { + return Exception(68, $"Parameter index '{parameterIndex}' was not valid for generated interop method '{method}'."); + } + + /// + /// The type of a parameter was not valid in a generated interop method. + /// + public static WellKnownInteropException MethodRewriteSourceParameterTypeMismatchError(TypeSignature parameterType, TypeSignature returnType, MethodDefinition method) + { + return Exception(69, $"Parameter variable of type '{parameterType}' cannot be used to marshal a value of type '{returnType}' in generated interop method '{method}'."); + } + /// /// Creates a new exception with the specified id and message. /// diff --git a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs index b78b155bf..791bc3859 100644 --- a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs @@ -199,6 +199,9 @@ public bool IsCustomMappedWindowsRuntimeNonGenericInterfaceType(InteropReference SignatureComparer.IgnoreVersion.Equals(type, interopReferences.IDisposable) || SignatureComparer.IgnoreVersion.Equals(type, interopReferences.IServiceProvider) || SignatureComparer.IgnoreVersion.Equals(type, interopReferences.ICommand) || + SignatureComparer.IgnoreVersion.Equals(type, interopReferences.IEnumerable) || + SignatureComparer.IgnoreVersion.Equals(type, interopReferences.IEnumerator) || + SignatureComparer.IgnoreVersion.Equals(type, interopReferences.IList) || SignatureComparer.IgnoreVersion.Equals(type, interopReferences.INotifyCollectionChanged) || SignatureComparer.IgnoreVersion.Equals(type, interopReferences.INotifyDataErrorInfo) || SignatureComparer.IgnoreVersion.Equals(type, interopReferences.INotifyPropertyChanged); diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs new file mode 100644 index 000000000..c733c37a2 --- /dev/null +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using AsmResolver.DotNet; +using AsmResolver.DotNet.Code.Cil; +using AsmResolver.DotNet.Collections; +using AsmResolver.DotNet.Signatures; +using AsmResolver.PE.DotNet.Cil; +using WindowsRuntime.InteropGenerator.Errors; +using WindowsRuntime.InteropGenerator.Generation; +using WindowsRuntime.InteropGenerator.References; +using static AsmResolver.PE.DotNet.Cil.CilOpCodes; + +namespace WindowsRuntime.InteropGenerator.Factories; + +/// +internal partial class InteropMethodRewriteFactory +{ + /// + /// Contains the logic for marshalling managed parameters (i.e. parameters that are passed to managed methods). + /// + public static class ManagedParameter + { + /// + /// Performs two-pass code generation on a target method to marshal an unmanaged parameter. + /// + /// The parameter type that needs to be marshalled. + /// The target method to perform two-pass code generation on. + /// The target IL instruction to replace with the right set of specialized instructions. + /// The index of the parameter to marshal. + /// The instance to use. + /// The emit state for this invocation. + /// The interop module being built. + public static void RewriteMethod( + TypeSignature parameterType, + MethodDefinition method, + CilInstruction marker, + int parameterIndex, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState, + ModuleDefinition module) + { + // Validate that we do have some IL body for the input method (this should always be the case) + if (method.CilMethodBody is not CilMethodBody body) + { + throw WellKnownInteropExceptions.MethodRewriteMissingBodyError(method); + } + + // If we didn't find the marker, it means the target method is either invalid + if (!body.Instructions.Contains(marker)) + { + throw WellKnownInteropExceptions.MethodRewriteMarkerInstructionNotFoundError(marker, method); + } + + // If we didn't find the marker, it means the target method is either invalid, or the + // supplied marker was incorrect (or the caller forgot to add it to the method body). + if ((uint)parameterIndex >= method.Parameters.Count) + { + throw WellKnownInteropExceptions.MethodRewriteParameterIndexNotValidError(parameterIndex, method); + } + + Parameter source = method.Parameters[parameterIndex]; + + // Validate that the ABI type matches + if (!SignatureComparer.IgnoreVersion.Equals(source.ParameterType, parameterType.GetAbiType(interopReferences))) + { + throw WellKnownInteropExceptions.MethodRewriteSourceParameterTypeMismatchError(source.ParameterType, parameterType, method); + } + + if (parameterType.IsValueType) + { + // If the return type is blittable, we can just load it directly it directly (simplest case) + if (parameterType.IsBlittable(interopReferences)) + { + body.Instructions.ReplaceRange(marker, CilInstruction.CreateLdarg(parameterIndex)); + } + else if (parameterType.IsConstructedKeyValuePairType(interopReferences)) + { + // If the type is some constructed 'KeyValuePair<,>' type, we use the generated marshaller + body.Instructions.ReplaceRange(marker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, emitState.LookupTypeDefinition(parameterType, "Marshaller").GetMethod("ConvertToManaged"))]); + } + else if (parameterType.IsConstructedNullableValueType(interopReferences)) + { + TypeSignature underlyingType = ((GenericInstanceTypeSignature)parameterType).TypeArguments[0]; + + // For 'Nullable' return types, we need the marshaller for the instantiated 'T' type (same as for return values) + ITypeDefOrRef marshallerType = GetValueTypeMarshallerType(underlyingType, interopReferences, emitState); + + // Get the right reference to the unboxing marshalling method to call + IMethodDefOrRef marshallerMethod = marshallerType.GetMethodDefOrRef( + name: "UnboxToManaged"u8, + signature: MethodSignature.CreateStatic( + returnType: parameterType, + parameterTypes: [module.CorLibTypeFactory.Void.MakePointerType()])); + + // Emit code similar to 'KeyValuePair<,>' above, to marshal the resulting 'Nullable' value + body.Instructions.ReplaceRange(marker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, marshallerMethod.Import(module))]); + } + else + { + // The last case handles all other value types. It doesn't matter if they possibly hold some unmanaged + // resources, as they're only being used as parameters. That means the caller is responsible for disposal. + ITypeDefOrRef marshallerType = GetValueTypeMarshallerType(parameterType, interopReferences, emitState); + + // Get the reference to 'ConvertToManaged' to produce the resulting value to return + IMethodDefOrRef marshallerMethod = marshallerType.GetMethodDefOrRef( + name: "ConvertToManaged"u8, + signature: MethodSignature.CreateStatic( + returnType: parameterType, + parameterTypes: [parameterType.GetAbiType(interopReferences)])); + + // We can directly call the marshaller and return it, no 'try/finally' complexity is needed + body.Instructions.ReplaceRange(marker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, marshallerMethod.Import(module))]); + } + } + else if (parameterType.IsTypeOfString()) + { + // When marshalling 'string' values, we must use 'HStringMarshaller' (the ABI type is not actually a COM object) + body.Instructions.ReplaceRange(marker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, interopReferences.HStringMarshallerConvertToManaged.Import(module))]); + } + else if (parameterType.IsTypeOfType(interopReferences)) + { + // When marshalling 'Type' values, we must use 'TypeMarshaller' (the ABI type is a value type) + body.Instructions.ReplaceRange(marker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, interopReferences.TypeMarshallerConvertToManaged.Import(module))]); + } + else if (parameterType is GenericInstanceTypeSignature) + { + // This case (constructed interfaces or delegates) is effectively identical to marshalling 'KeyValuePair<,>' values + body.Instructions.ReplaceRange(marker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, emitState.LookupTypeDefinition(parameterType, "Marshaller").GetMethod("ConvertToManaged"))]); + } + else + { + // Get the marshaller type for all other reference types + ITypeDefOrRef marshallerType = GetReferenceTypeMarshallerType(parameterType, interopReferences, emitState); + + // Get the marshalling method, with the parameter type always just being 'void*' here too + IMethodDefOrRef marshallerMethod = marshallerType.GetMethodDefOrRef( + name: "ConvertToManaged"u8, + signature: MethodSignature.CreateStatic( + returnType: parameterType, + parameterTypes: [module.CorLibTypeFactory.Void.MakePointerType()])); + + // Marshal the value and release the original interface pointer + body.Instructions.ReplaceRange(marker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, marshallerMethod.Import(module))]); + } + } + } +} \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs index 3bac81fce..674e05df2 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs @@ -60,6 +60,12 @@ public static void RewriteMethod( throw WellKnownInteropExceptions.MethodRewriteSourceLocalNotFoundError(source, method); } + // Validate that the ABI type matches + if (!SignatureComparer.IgnoreVersion.Equals(source.VariableType, returnType.GetAbiType(interopReferences))) + { + throw WellKnownInteropExceptions.MethodRewriteSourceLocalTypeMismatchError(source.VariableType, returnType, method); + } + if (returnType.IsValueType) { // If the return type is blittable, we can always return it directly (simplest case) diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.cs index 985865d84..39db3a7a5 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.cs @@ -84,7 +84,9 @@ private static ITypeDefOrRef GetReferenceTypeMarshallerType( } // For custom-mapped types, get the marshaller type from 'WinRT.Runtime.dll' - if (type.IsCustomMappedWindowsRuntimeNonGenericInterfaceType(interopReferences) || + if (type.IsTypeOfType(interopReferences) || + type.IsTypeOfException(interopReferences) || + type.IsCustomMappedWindowsRuntimeNonGenericInterfaceType(interopReferences) || type.IsCustomMappedWindowsRuntimeNonGenericDelegateType(interopReferences)) { return interopReferences.WindowsRuntimeModule.CreateTypeReference( diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index c5d2adf96..e99445de9 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -293,6 +293,7 @@ private static void DefineGenericDelegateTypes( get_IidMethod: get_IidMethod, get_ReferenceIidMethod: get_ReferenceIidMethod, interopReferences: interopReferences, + emitState: emitState, module: module, marshallerType: out TypeDefinition marshallerType); @@ -300,6 +301,7 @@ private static void DefineGenericDelegateTypes( delegateType: typeSignature, interopDefinitions: interopDefinitions, interopReferences: interopReferences, + emitState: emitState, module: module, implType: out TypeDefinition delegateImplType); @@ -366,9 +368,6 @@ private static void DefineGenericDelegateTypes( } else if (SignatureComparer.IgnoreVersion.Equals(typeSignature.GenericType, interopReferences.VectorChangedEventHandler1)) { - // We need the marshaller type for the 'IObservableVector' implementation - emitState.TrackTypeDefinition(marshallerType, typeSignature, "Marshaller"); - InteropTypeDefinitionBuilder.EventSource.VectorChangedEventHandler1( delegateType: typeSignature, marshallerType: marshallerType, @@ -379,9 +378,6 @@ private static void DefineGenericDelegateTypes( } else if (SignatureComparer.IgnoreVersion.Equals(typeSignature.GenericType, interopReferences.MapChangedEventHandler2)) { - // We need the marshaller type for the 'IObservableMap' implementation - emitState.TrackTypeDefinition(marshallerType, typeSignature, "Marshaller"); - InteropTypeDefinitionBuilder.EventSource.MapChangedEventHandler2( delegateType: typeSignature, marshallerType: marshallerType, @@ -390,15 +386,6 @@ private static void DefineGenericDelegateTypes( module: module, eventSourceType: out _); } - else if (SignatureComparer.IgnoreVersion.Equals(typeSignature.GenericType, interopReferences.AsyncActionProgressHandler1) || - SignatureComparer.IgnoreVersion.Equals(typeSignature.GenericType, interopReferences.AsyncActionWithProgressCompletedHandler1) || - SignatureComparer.IgnoreVersion.Equals(typeSignature.GenericType, interopReferences.AsyncOperationCompletedHandler1) || - SignatureComparer.IgnoreVersion.Equals(typeSignature.GenericType, interopReferences.AsyncOperationProgressHandler2) || - SignatureComparer.IgnoreVersion.Equals(typeSignature.GenericType, interopReferences.AsyncOperationWithProgressCompletedHandler2)) - { - // We need these marshaller types for the various async type implementations - emitState.TrackTypeDefinition(marshallerType, typeSignature, "Marshaller"); - } } catch (Exception e) { @@ -477,9 +464,9 @@ private static void DefineIEnumeratorTypes( module: module, out TypeDefinition enumeratorComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IEnumerator1.Marshaller( - enumeratorType: typeSignature, - enumeratorComWrappersCallbackType: enumeratorComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: enumeratorComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, emitState: emitState, @@ -600,9 +587,9 @@ private static void DefineIEnumerableTypes( module: module, out TypeDefinition enumerableComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IEnumerable1.Marshaller( - enumerableType: typeSignature, - enumerableComWrappersCallbackType: enumerableComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: enumerableComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, emitState: emitState, @@ -723,9 +710,9 @@ private static void DefineIReadOnlyListTypes( module: module, out TypeDefinition readOnlyListComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IReadOnlyList1.Marshaller( - readOnlyListType: typeSignature, - readOnlyListComWrappersCallbackType: readOnlyListComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: readOnlyListComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, emitState: emitState, @@ -855,9 +842,9 @@ private static void DefineIListTypes( module: module, out TypeDefinition listComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IList1.Marshaller( - listType: typeSignature, - listComWrappersCallbackType: listComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: listComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, emitState: emitState, @@ -979,9 +966,9 @@ private static void DefineIReadOnlyDictionaryTypes( module: module, out TypeDefinition readOnlyDictionaryComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IReadOnlyDictionary2.Marshaller( - readOnlyDictionaryType: typeSignature, - readOnlyDictionaryComWrappersCallbackType: readOnlyDictionaryComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: readOnlyDictionaryComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, emitState: emitState, @@ -1112,9 +1099,9 @@ private static void DefineIDictionaryTypes( module: module, out TypeDefinition dictionaryComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IDictionary2.Marshaller( - dictionaryType: typeSignature, - dictionaryComWrappersCallbackType: dictionaryComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: dictionaryComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, emitState: emitState, @@ -1309,9 +1296,9 @@ private static void DefineIMapChangedEventArgsTypes( module: module, out TypeDefinition argsComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IMapChangedEventArgs1.Marshaller( - argsType: typeSignature, - argsComWrappersCallbackType: argsComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: argsComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, emitState: emitState, @@ -1426,11 +1413,12 @@ private static void DefineIObservableVectorTypes( module: module, out TypeDefinition comWrappersMarshallerType); - InteropTypeDefinitionBuilder.IObservableVector1.Marshaller( - vectorType: typeSignature, - vectorComWrappersCallbackType: comWrappersMarshallerType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: comWrappersMarshallerType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, + emitState: emitState, module: module, marshallerType: out TypeDefinition marshallerType); @@ -1542,11 +1530,12 @@ private static void DefineIObservableMapTypes( module: module, out TypeDefinition comWrappersMarshallerType); - InteropTypeDefinitionBuilder.IObservableMap2.Marshaller( - mapType: typeSignature, - mapComWrappersCallbackType: comWrappersMarshallerType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: comWrappersMarshallerType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, + emitState: emitState, module: module, marshallerType: out TypeDefinition marshallerType); @@ -1648,11 +1637,12 @@ private static void DefineIAsyncActionWithProgressTypes( module: module, out TypeDefinition actionComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.Marshaller( - actionType: typeSignature, - operationComWrappersCallbackType: actionComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: actionComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, + emitState: emitState, module: module, marshallerType: out TypeDefinition marshallerType); @@ -1754,11 +1744,12 @@ private static void DefineIAsyncOperationTypes( module: module, out TypeDefinition operationComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IAsyncOperation1.Marshaller( - operationType: typeSignature, - operationComWrappersCallbackType: operationComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: operationComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, + emitState: emitState, module: module, marshallerType: out TypeDefinition marshallerType); @@ -1860,11 +1851,12 @@ private static void DefineIAsyncOperationWithProgressTypes( module: module, out TypeDefinition operationComWrappersMarshallerType); - InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.Marshaller( - operationType: typeSignature, - operationComWrappersCallbackType: operationComWrappersCallbackType, + InteropTypeDefinitionBuilder.Marshaller( + typeSignature: typeSignature, + interfaceComWrappersCallbackType: operationComWrappersCallbackType, get_IidMethod: get_IidMethod, interopReferences: interopReferences, + emitState: emitState, module: module, marshallerType: out TypeDefinition marshallerType); @@ -2014,23 +2006,35 @@ private static void RewriteMethodDefinitions( switch (rewriteInfo) { // Rewrite return values for managed types - case ReturnTypeMethodRewriteInfo returnTypeInfo: + case MethodRewriteInfo.ReturnValue returnValueInfo: InteropMethodRewriteFactory.ReturnValue.RewriteMethod( - returnType: returnTypeInfo.Type, - method: returnTypeInfo.Method, - marker: returnTypeInfo.Marker, - source: returnTypeInfo.Source, + returnType: returnValueInfo.Type, + method: returnValueInfo.Method, + marker: returnValueInfo.Marker, + source: returnValueInfo.Source, interopReferences: interopReferences, emitState: emitState, module: module); break; // Rewrite return values for native types - case RetValTypeMethodRewriteInfo retValTypeInfo: + case MethodRewriteInfo.RetVal retValInfo: InteropMethodRewriteFactory.RetVal.RewriteMethod( - retValType: retValTypeInfo.Type, - method: retValTypeInfo.Method, - marker: retValTypeInfo.Marker, + retValType: retValInfo.Type, + method: retValInfo.Method, + marker: retValInfo.Marker, + interopReferences: interopReferences, + emitState: emitState, + module: module); + break; + + // Rewrite managed parameters + case MethodRewriteInfo.ManagedParameter managedParameterInfo: + InteropMethodRewriteFactory.ManagedParameter.RewriteMethod( + parameterType: managedParameterInfo.Type, + method: managedParameterInfo.Method, + marker: managedParameterInfo.Marker, + parameterIndex: managedParameterInfo.ParameterIndex, interopReferences: interopReferences, emitState: emitState, module: module); diff --git a/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs b/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs index 181f3ba93..52a4f2a8c 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs @@ -88,7 +88,7 @@ public TypeDefinition LookupTypeDefinition(TypeSignature typeSignature, string k /// /// /// - /// + /// public void TrackReturnValueMethodRewrite( TypeSignature returnType, MethodDefinition method, @@ -97,7 +97,7 @@ public void TrackReturnValueMethodRewrite( { ThrowIfReadOnly(); - _methodRewriteInfos.Add(new ReturnTypeMethodRewriteInfo + _methodRewriteInfos.Add(new MethodRewriteInfo.ReturnValue { Type = returnType, Method = method, @@ -119,7 +119,7 @@ public void TrackRetValValueMethodRewrite( { ThrowIfReadOnly(); - _methodRewriteInfos.Add(new RetValTypeMethodRewriteInfo + _methodRewriteInfos.Add(new MethodRewriteInfo.RetVal { Type = retValType, Method = method, @@ -127,6 +127,30 @@ public void TrackRetValValueMethodRewrite( }); } + /// + /// Tracks a method rewrite that involves loading a parameter in the specified method. + /// + /// + /// + /// + /// + public void TrackManagedParameterMethodRewrite( + TypeSignature paraneterType, + MethodDefinition method, + CilInstruction marker, + int parameterIndex) + { + ThrowIfReadOnly(); + + _methodRewriteInfos.Add(new MethodRewriteInfo.ManagedParameter + { + Type = paraneterType, + Method = method, + Marker = marker, + ParameterIndex = parameterIndex + }); + } + /// /// Enumerates all instances with info on two-pass code generation steps to perform. /// diff --git a/src/WinRT.Interop.Generator/Helpers/TypeMapping.cs b/src/WinRT.Interop.Generator/Helpers/TypeMapping.cs index c4a3ba39d..deec11afb 100644 --- a/src/WinRT.Interop.Generator/Helpers/TypeMapping.cs +++ b/src/WinRT.Interop.Generator/Helpers/TypeMapping.cs @@ -51,6 +51,7 @@ private readonly record struct MappedType( new("System.ComponentModel.PropertyChangedEventHandler", new("Microsoft.UI.Xaml.Data", "PropertyChangedEventHandler")), new("System.Windows.Input.ICommand", new("Microsoft.UI.Xaml.Input", "ICommand")), new("System.Collections.IEnumerable", new("Microsoft.UI.Xaml.Interop", "IBindableIterable")), + new("System.Collections.IEnumerator", new("Microsoft.UI.Xaml.Interop", "IBindableIterator")), new("System.Collections.IList", new("Microsoft.UI.Xaml.Interop", "IBindableVector")), new("System.Collections.Specialized.INotifyCollectionChanged", new("Microsoft.UI.Xaml.Interop", "INotifyCollectionChanged")), new("System.Collections.Specialized.NotifyCollectionChangedAction", new("Microsoft.UI.Xaml.Interop", "NotifyCollectionChangedAction", "enum(Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction;i4)")), @@ -94,6 +95,7 @@ private readonly record struct MappedType( new("Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction", new("Windows.UI.Xaml.Interop", "NotifyCollectionChangedAction", "enum(Windows.UI.Xaml.Interop.NotifyCollectionChangedAction;i4)")), new("Microsoft.UI.Xaml.Interop.INotifyCollectionChanged", new("Windows.UI.Xaml.Interop", "INotifyCollectionChanged")), new("Microsoft.UI.Xaml.Interop.IBindableIterable", new("Windows.UI.Xaml.Interop", "IBindableIterable")), + new("Microsoft.UI.Xaml.Interop.IBindableIterator", new("Windows.UI.Xaml.Interop", "IBindableIterator")), new("Microsoft.UI.Xaml.Interop.IBindableVector", new("Windows.UI.Xaml.Interop", "IBindableVector")), new("Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventHandler", new("Windows.UI.Xaml.Interop", "NotifyCollectionChangedEventHandler")), new("Microsoft.UI.Xaml.Input.ICommand", new("Windows.UI.Xaml.Input", "ICommand")), diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs new file mode 100644 index 000000000..5e18a8788 --- /dev/null +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace WindowsRuntime.InteropGenerator.Models; + +/// +internal partial class MethodRewriteInfo +{ + /// + /// Contains info for a target method for two-pass IL generation, for a managed parameter. + /// + /// + public sealed class ManagedParameter : MethodRewriteInfo + { + /// + public required int ParameterIndex { get; init; } + + /// + public override int CompareTo(MethodRewriteInfo? other) + { + if (other is null) + { + return 1; + } + + if (ReferenceEquals(this, other)) + { + return 0; + } + + // If the input object is of a different type, just sort alphabetically based on the type name + if (other is not ManagedParameter info) + { + return typeof(ManagedParameter).FullName!.CompareTo(other.GetType().FullName!); + } + + int result = CompareByMethodRewriteInfo(other); + + // If the two items are already not equal, we can stop here + if (result != 0) + { + return result; + } + + // Lastly, compare by parameter index + return ParameterIndex.CompareTo(info.ParameterIndex); + } + } +} diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.RetVal.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.RetVal.cs new file mode 100644 index 000000000..d86d21e98 --- /dev/null +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.RetVal.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace WindowsRuntime.InteropGenerator.Models; + +/// +internal partial class MethodRewriteInfo +{ + /// + /// Contains info for a target method for two-pass IL generation, for an unmanaged [retval] value. + /// + /// + public sealed class RetVal : MethodRewriteInfo + { + /// + public override int CompareTo(MethodRewriteInfo? other) + { + if (other is null) + { + return 1; + } + + if (ReferenceEquals(this, other)) + { + return 0; + } + + // Same logic as in 'ReturnValue', or just compare the base state + return other is not RetVal + ? typeof(RetVal).FullName!.CompareTo(other.GetType().FullName!) + : CompareByMethodRewriteInfo(other); + } + } +} diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ReturnValue.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ReturnValue.cs new file mode 100644 index 000000000..6fdf333ca --- /dev/null +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ReturnValue.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using AsmResolver.DotNet.Code.Cil; + +namespace WindowsRuntime.InteropGenerator.Models; + +/// +internal partial class MethodRewriteInfo +{ + /// + /// Contains info for a target method for two-pass IL generation, for a managed return value. + /// + /// + public sealed class ReturnValue : MethodRewriteInfo + { + /// + public required CilLocalVariable Source { get; init; } + + /// + public override int CompareTo(MethodRewriteInfo? other) + { + if (other is null) + { + return 1; + } + + if (ReferenceEquals(this, other)) + { + return 0; + } + + // If the input object is of a different type, just sort alphabetically based on the type name + if (other is not ReturnValue info) + { + return typeof(ReturnValue).FullName!.CompareTo(other.GetType().FullName!); + } + + int result = CompareByMethodRewriteInfo(other); + + // If the two items are already not equal, we can stop here + if (result != 0) + { + return result; + } + + int leftIndex = Method.CilMethodBody?.LocalVariables.IndexOf(Source) ?? -1; + int rightIndex = other.Method.CilMethodBody?.LocalVariables.IndexOf(info.Source) ?? -1; + + // Lastly, compare by order of instructions within the target method. + // There's no concern about stable sorting with respect to objects + // where the instructions are missing, as 'cswinrtgen' will fail. + return leftIndex.CompareTo(rightIndex); + } + } +} diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.cs index 6844e7a8e..0790df9fe 100644 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.cs +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.cs @@ -12,7 +12,7 @@ namespace WindowsRuntime.InteropGenerator.Models; /// /// Contains generic info for a target method for two-pass IL generation. /// -internal abstract class MethodRewriteInfo : IComparable +internal abstract partial class MethodRewriteInfo : IComparable { /// /// The type of the value that needs to be marshalled. diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/RetValTypeMethodRewriteInfo.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/RetValTypeMethodRewriteInfo.cs deleted file mode 100644 index 036e7f6b3..000000000 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/RetValTypeMethodRewriteInfo.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace WindowsRuntime.InteropGenerator.Models; - -/// -/// Contains info for a target method for two-pass IL generation, for an unmanaged [retval] value. -/// -/// -internal sealed class RetValTypeMethodRewriteInfo : MethodRewriteInfo -{ - /// - public override int CompareTo(MethodRewriteInfo? other) - { - if (other is null) - { - return 1; - } - - if (ReferenceEquals(this, other)) - { - return 0; - } - - // Same logic as in 'ReturnTypeMethodRewriteInfo', or just compare the base state - return other is not RetValTypeMethodRewriteInfo - ? typeof(RetValTypeMethodRewriteInfo).FullName!.CompareTo(other.GetType().FullName!) - : CompareByMethodRewriteInfo(other); - } -} diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/ReturnTypeMethodRewriteInfo.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/ReturnTypeMethodRewriteInfo.cs deleted file mode 100644 index d22d5c562..000000000 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/ReturnTypeMethodRewriteInfo.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using AsmResolver.DotNet.Code.Cil; - -namespace WindowsRuntime.InteropGenerator.Models; - -/// -/// Contains info for a target method for two-pass IL generation, for a managed return value. -/// -/// -internal sealed class ReturnTypeMethodRewriteInfo : MethodRewriteInfo -{ - /// - public required CilLocalVariable Source { get; init; } - - /// - public override int CompareTo(MethodRewriteInfo? other) - { - if (other is null) - { - return 1; - } - - if (ReferenceEquals(this, other)) - { - return 0; - } - - // If the input object is of a different type, just sort alphabetically based on the type name - if (other is not ReturnTypeMethodRewriteInfo info) - { - return typeof(ReturnTypeMethodRewriteInfo).FullName!.CompareTo(other.GetType().FullName!); - } - - int result = CompareByMethodRewriteInfo(other); - - // If the two items are already not equal, we can stop here - if (result != 0) - { - return result; - } - - int leftIndex = Method.CilMethodBody?.LocalVariables.IndexOf(Source) ?? -1; - int rightIndex = other.Method.CilMethodBody?.LocalVariables.IndexOf(info.Source) ?? -1; - - // Lastly, compare by order of instructions within the target method. - // There's no concern about stable sorting with respect to objects - // where the instructions are missing, as 'cswinrtgen' will fail. - return leftIndex.CompareTo(rightIndex); - } -} diff --git a/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs b/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs index 2a4ebbe32..e95112ff3 100644 --- a/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs +++ b/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs @@ -90,6 +90,18 @@ _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.I => "Windows_Foundation_Collections_IVectorChangedEventArgs", // XAML types + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerable) && useWindowsUIXamlProjections + => "Windows_UI_Xaml_Interop_IBindableIterable", + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerable) + => "Microsoft_UI_Xaml_Interop_IBindableIterable", + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerator) && useWindowsUIXamlProjections + => "Windows_UI_Xaml_Interop_IBindableIterator", + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerator) + => "Microsoft_UI_Xaml_Interop_IBindableIterator", + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IList) && useWindowsUIXamlProjections + => "Windows_UI_Xaml_Interop_IBindableVector", + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IList) + => "Microsoft_UI_Xaml_Interop_IBindableVector", _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.INotifyCollectionChanged) && useWindowsUIXamlProjections => "Windows_UI_Xaml_Interop_INotifyCollectionChanged", _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.INotifyCollectionChanged) @@ -142,12 +154,8 @@ _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.E => new Guid("9DE1C535-6AE1-11E0-84E1-18A905BCC53F"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.KeyValuePair2) => new Guid("02B51929-C1C4-4A7E-8940-0312B5C18500"), - _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerable) - => new Guid("FAA585EA-6214-4217-AFDA-7F46DE5869B3"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerable1) => new Guid("FAA585EA-6214-4217-AFDA-7F46DE5869B3"), - _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerator) - => new Guid("6A79E863-4300-459A-9966-CBB660963EE1"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerator1) => new Guid("6A79E863-4300-459A-9966-CBB660963EE1"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.AsyncOperationWithProgressCompletedHandler2) @@ -156,8 +164,6 @@ _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.A => new Guid("9D534225-231F-55E7-A6D0-6C938E2D9160"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.MapChangedEventHandler2) => new Guid("19046F0B-CF81-5DEC-BBB2-7CC250DA8B8B"), - _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IList) - => new Guid("393DE7DE-6FD0-4C0D-BB71-47244A113E93"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IList1) => new Guid("0E3F106F-A266-50A1-8043-C90FCF3844F6"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IReadOnlyList1) @@ -190,6 +196,12 @@ _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.I => new Guid("575933DF-34FE-4480-AF15-07691F3D5D9B"), // XAML types + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerable) + => new Guid("FAA585EA-6214-4217-AFDA-7F46DE5869B3"), + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IEnumerator) + => new Guid("6A79E863-4300-459A-9966-CBB660963EE1"), + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IList) + => new Guid("393DE7DE-6FD0-4C0D-BB71-47244A113E93"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.INotifyCollectionChanged) && useWindowsUIXamlProjections => new Guid("28B167D5-1A31-465B-9B25-D5C3AE686C40"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.INotifyCollectionChanged)