diff --git a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets index 0584b2e2b..d2405c128 100644 --- a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets +++ b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets @@ -155,9 +155,9 @@ Copyright (C) Microsoft Corporation. All rights reserved. @@ -177,6 +177,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. ReferenceAssemblyPaths="@(_ReferenceAssemblyPaths)" ImplementationAssemblyPaths="@(ReferencePath)" OutputAssemblyPath="@(IntermediateAssembly)" + WinRTProjectionAssemblyPath="$(_CsWinRTGeneratorMergedProjectionAssemblyPath)" InteropAssemblyDirectory="$(CsWinRTGeneratorInteropAssemblyDirectory)" DebugReproDirectory="$(CsWinRTGeneratorDebugReproDirectory)" CsWinRTToolsDirectory="$(CsWinRTGenEffectiveToolsDirectory)" diff --git a/src/RunCsWinRTGeneratorTask/RunCsWinRTGenerator.cs b/src/RunCsWinRTGeneratorTask/RunCsWinRTGenerator.cs index 0aec23905..2cc0240c7 100644 --- a/src/RunCsWinRTGeneratorTask/RunCsWinRTGenerator.cs +++ b/src/RunCsWinRTGeneratorTask/RunCsWinRTGenerator.cs @@ -43,6 +43,17 @@ public sealed class RunCsWinRTGenerator : ToolTask [Required] public ITaskItem[]? OutputAssemblyPath { get; set; } + /// + /// Gets or sets the path to the WinRT merged projection assembly. + /// + [Required] + public ITaskItem? WinRTProjectionAssemblyPath { get; set; } + + /// + /// Gets or sets the path to the WinRT merged component assembly generated for authoring scenarios. + /// + public ITaskItem? WinRTComponentAssemblyPath { get; set; } + /// /// Gets or sets the directory where the generated interop assembly will be placed. /// @@ -149,6 +160,13 @@ protected override bool ValidateParameters() return false; } + if (WinRTProjectionAssemblyPath is null) + { + Log.LogWarning("Invalid 'WinRTProjectionAssemblyPath' input."); + + return false; + } + if (InteropAssemblyDirectory is null || !Directory.Exists(InteropAssemblyDirectory)) { Log.LogWarning("Generated assembly directory '{0}' is invalid or does not exist.", InteropAssemblyDirectory); @@ -236,6 +254,8 @@ protected override string GenerateResponseFileCommands() AppendResponseFileCommand(args, "--reference-assembly-paths", referenceAssemblyPathsArg); AppendResponseFileCommand(args, "--implementation-assembly-paths", implementationAssemblyPathsArg); AppendResponseFileCommand(args, "--output-assembly-path", EffectiveOutputAssemblyItemSpec); + AppendResponseFileCommand(args, "--winrt-projection-assembly-path", WinRTProjectionAssemblyPath!.ItemSpec); + AppendResponseFileOptionalCommand(args, "--winrt-component-assembly-path", WinRTComponentAssemblyPath?.ItemSpec); AppendResponseFileCommand(args, "--generated-assembly-directory", InteropAssemblyDirectory!); AppendResponseFileOptionalCommand(args, "--debug-repro-directory", DebugReproDirectory); AppendResponseFileCommand(args, "--use-windows-ui-xaml-projections", UseWindowsUIXamlProjections.ToString()); diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.ICommand.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.ICommand.cs index 81fd596ef..3cd937e73 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.ICommand.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.ICommand.cs @@ -20,11 +20,13 @@ public static class ICommand /// /// Creates a new type definition for the interface implementation of the interface. /// + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. /// The resulting interface implementation type. public static void InterfaceImpl( + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -42,7 +44,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(interfaceType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(interfaceType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { new InterfaceImplementation(interfaceType.ToTypeDefOrRef()) } }; diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyCollectionChanged.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyCollectionChanged.cs index 1d0da3b11..3af1f9f51 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyCollectionChanged.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyCollectionChanged.cs @@ -20,11 +20,13 @@ public static class INotifyCollectionChanged /// /// Creates a new type definition for the interface implementation of the interface. /// + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. /// The resulting interface implementation type. public static void InterfaceImpl( + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -42,7 +44,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(interfaceType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(interfaceType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { new InterfaceImplementation(interfaceType.ToTypeDefOrRef()) } }; diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyPropertyChanged.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyPropertyChanged.cs index a42e81432..4dfd2169b 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyPropertyChanged.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyPropertyChanged.cs @@ -20,11 +20,13 @@ public static class INotifyPropertyChanged /// /// Creates a new type definition for the interface implementation of the interface. /// + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. /// The resulting interface implementation type. public static void InterfaceImpl( + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -42,7 +44,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(interfaceType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(interfaceType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { new InterfaceImplementation(interfaceType.ToTypeDefOrRef()) } }; diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs index 189e28a93..f7f08b1f1 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs @@ -25,10 +25,12 @@ internal static partial class DynamicCustomMappedTypeMapEntriesBuilder /// Defines all assembly attributes for dynamic custom-mapped type map entries. /// /// The arguments for this invocation. + /// The instance to use. /// The instance to use. /// The interop module being built. public static void AssemblyAttributes( InteropGeneratorArgs args, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module) { @@ -60,16 +62,19 @@ public static void AssemblyAttributes( useComWrappersMarshallerAttribute: true); ICommandInterfaceType( + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); INotifyCollectionChangedInterfaceType( + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); INotifyPropertyChangedInterfaceType( + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); @@ -185,10 +190,12 @@ private static void InterfaceType( /// /// Creates a new custom attribute value for for the interface type. /// + /// The instance to use. /// The instance to use. /// The module that the attribute will be used from. /// Whether to use Windows.UI.Xaml projections. private static void ICommandInterfaceType( + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections) @@ -215,6 +222,7 @@ private static void ICommandInterfaceType( // Define the 'InterfaceImpl' type for the 'ICommand' interface type ICommand.InterfaceImpl( + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: useWindowsUIXamlProjections, @@ -239,10 +247,12 @@ private static void ICommandInterfaceType( /// /// Creates a new custom attribute value for for the interface type. /// + /// The instance to use. /// The instance to use. /// The module that the attribute will be used from. /// Whether to use Windows.UI.Xaml projections. private static void INotifyCollectionChangedInterfaceType( + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections) @@ -269,6 +279,7 @@ private static void INotifyCollectionChangedInterfaceType( // Define the 'InterfaceImpl' type for the 'INotifyCollectionChanged' interface type INotifyCollectionChanged.InterfaceImpl( + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: useWindowsUIXamlProjections, @@ -293,10 +304,12 @@ private static void INotifyCollectionChangedInterfaceType( /// /// Creates a new custom attribute value for for the interface type. /// + /// The instance to use. /// The instance to use. /// The module that the attribute will be used from. /// Whether to use Windows.UI.Xaml projections. private static void INotifyPropertyChangedInterfaceType( + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections) @@ -323,6 +336,7 @@ private static void INotifyPropertyChangedInterfaceType( // Define the 'InterfaceImpl' type for the 'INotifyPropertyChanged' interface type INotifyPropertyChanged.InterfaceImpl( + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: useWindowsUIXamlProjections, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index c7732764c..29754cd24 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -45,7 +45,7 @@ public static void IIDs( name: InteropUtf8NameFactory.TypeName(delegateType), interopDefinitions: interopDefinitions, interopReferences: interopReferences, - iid: GuidGenerator.CreateIID(delegateType, interopReferences, useWindowsUIXamlProjections), + iid: GuidGenerator.CreateIID(delegateType, interopDefinitions, interopReferences, useWindowsUIXamlProjections), out get_IidMethod); // 'IReference' IID, which uses a boxed type signature to represent it. @@ -58,7 +58,7 @@ public static void IIDs( name: InteropUtf8NameFactory.TypeName(delegateType, "Reference"), interopDefinitions: interopDefinitions, interopReferences: interopReferences, - iid: GuidGenerator.CreateIID(delegateType.MakeBoxedType(), interopReferences, useWindowsUIXamlProjections), + iid: GuidGenerator.CreateIID(delegateType.MakeBoxedType(), interopDefinitions, interopReferences, useWindowsUIXamlProjections), out get_ReferenceIidMethod); } diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs index c4dcebaf9..28dfd40f0 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs @@ -231,6 +231,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the async action type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -238,6 +239,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature actionType, TypeDefinition actionMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -255,7 +257,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(actionType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(actionType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs index 036fd539b..5b2b91cd3 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs @@ -185,6 +185,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the async operation type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -192,6 +193,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature operationType, TypeDefinition operationMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -209,7 +211,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(operationType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(operationType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs index 22e336f03..ffdf9de7e 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs @@ -225,6 +225,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the async operation type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -232,6 +233,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature operationType, TypeDefinition operationMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -250,7 +252,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(operationType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(operationType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs index 4841043e6..a2733e146 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs @@ -687,6 +687,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -694,6 +695,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature dictionaryType, TypeDefinition dictionaryMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -715,7 +717,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(dictionaryType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(dictionaryType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs index 79b61b694..076be53f1 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs @@ -341,6 +341,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -348,6 +349,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature enumerableType, TypeDefinition iterableMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -365,7 +367,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(enumerableType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(enumerableType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs index efb9172fd..41cc1f4ce 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs @@ -44,7 +44,7 @@ public static void IID( name: InteropUtf8NameFactory.TypeName(enumeratorType), interopDefinitions: interopDefinitions, interopReferences: interopReferences, - iid: GuidGenerator.CreateIID(enumeratorType, interopReferences, useWindowsUIXamlProjections), + iid: GuidGenerator.CreateIID(enumeratorType, interopDefinitions, interopReferences, useWindowsUIXamlProjections), out get_IidMethod); // Track the IID method, as it's needed to marshal enumerators from the 'IIterable.First' implementation @@ -360,6 +360,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -367,6 +368,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature enumeratorType, TypeDefinition iteratorMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -384,7 +386,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(enumeratorType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(enumeratorType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs index e47d82985..a7d654252 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs @@ -612,6 +612,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -619,6 +620,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature listType, TypeDefinition listMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -638,7 +640,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(listType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(listType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs index 3c57d3c18..14c3c7f17 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs @@ -173,6 +173,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the args type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -180,6 +181,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature argsType, TypeDefinition argsMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -197,7 +199,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(argsType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(argsType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { new InterfaceImplementation(argsType.ToTypeDefOrRef()) } }; diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs index 143fc4ddf..3e99bbbc7 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs @@ -301,6 +301,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the map type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -308,6 +309,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature mapType, TypeDefinition mapMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -332,7 +334,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(mapType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(mapType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs index 4d2b13076..8bca73702 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs @@ -296,6 +296,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the vector type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -303,6 +304,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature vectorType, TypeDefinition vectorMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -320,7 +322,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(vectorType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(vectorType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs index db114d164..0e60639f9 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs @@ -374,6 +374,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -381,6 +382,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature readOnlyDictionaryType, TypeDefinition readOnlyDictionaryMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -402,7 +404,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(readOnlyDictionaryType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(readOnlyDictionaryType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs index 9246bb4c1..d9c44335f 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs @@ -277,6 +277,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -284,6 +285,7 @@ public static void ComWrappersMarshallerAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature readOnlyListType, TypeDefinition readOnlyListMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -303,7 +305,7 @@ public static void InterfaceImpl( CustomAttributes = { new CustomAttribute(interopReferences.DynamicInterfaceCastableImplementationAttribute_ctor), - InteropCustomAttributeFactory.Guid(readOnlyListType, interopReferences, useWindowsUIXamlProjections) + InteropCustomAttributeFactory.Guid(readOnlyListType, interopDefinitions, interopReferences, useWindowsUIXamlProjections) }, Interfaces = { diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs index 29137981b..44c46aa2a 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs @@ -45,7 +45,7 @@ public static void IID( name: InteropUtf8NameFactory.TypeName(interfaceType), interopDefinitions: interopDefinitions, interopReferences: interopReferences, - iid: GuidGenerator.CreateIID(interfaceType, interopReferences, useWindowsUIXamlProjections), + iid: GuidGenerator.CreateIID(interfaceType, interopDefinitions, interopReferences, useWindowsUIXamlProjections), out get_IidMethod); } diff --git a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs index 4ac565d91..accbcdc5a 100644 --- a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs +++ b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs @@ -722,6 +722,30 @@ public static WellKnownInteropWarning ExceededNumberOfExposedWindowsRuntimeInter return Warning(84, $"Exposed type '{type}' exceeded the maximum limit of 128 projected Windows Runtime interfaces implemented: all exceeding interfaces will not be included in the set of available COM interface entries."); } + /// + /// Invalid reference to a reserved .dll name. + /// + public static WellKnownInteropException ReservedDllNameReferenceError(string dllName) + { + return Exception(85, $"Invalid .dll reference to the reserved .dll name '{dllName}': it is not valid to reference .dll-s with a name starting with the 'WinRT.' prefix."); + } + + /// + /// Mismatched path for a reserved .dll file. + /// + public static WellKnownInteropException ReservedDllOriginalPathMismatch(string dllName) + { + return Exception(86, $"The reserved '{dllName}' assembly has a mismatching path with the item supplied via '$(ReferencePath)'."); + } + + /// + /// Mismatched path for a reserved .dll file. + /// + public static WellKnownInteropException ReservedDllOriginalPathMismatchFromDebugRepro(string dllName) + { + return Exception(87, $"The reserved '{dllName}' assembly has a mismatching path with the item supplied via '$(ReferencePath)': the debug repro canot be generated."); + } + /// /// Creates a new exception with the specified id and message. /// diff --git a/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.TypesLookup.cs b/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.TypesLookup.cs new file mode 100644 index 000000000..cce095090 --- /dev/null +++ b/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.TypesLookup.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using AsmResolver; +using AsmResolver.DotNet; + +namespace WindowsRuntime.InteropGenerator; + +/// +internal partial class ModuleDefinitionExtensions +{ + /// + /// Gets a lookup of top level types for a given module. + /// + /// The input instance. + /// The resulting top level types lookup. + public static IReadOnlyDictionary<(Utf8String? Namespace, Utf8String? Name), TypeDefinition> GetTopLevelTypesLookup(this ModuleDefinition module) + { + return TopLevelTypesLookupCache.Instance.GetOrAdd( + key: module, + valueFactory: static module => module.TopLevelTypes.ToFrozenDictionary(static type => (type.Namespace, type.Name))); + } +} + +/// +/// Contains a shared cache of top level types lookups, to speed up search operations. +/// +file static class TopLevelTypesLookupCache +{ + /// + /// The singleton top level types lookups map. + /// + public static readonly ConditionalWeakTable> Instance = []; +} \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.cs b/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.cs index 85c80c7fd..e4a8fba78 100644 --- a/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/ModuleDefinitionExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using AsmResolver; using AsmResolver.DotNet; @@ -16,7 +17,7 @@ namespace WindowsRuntime.InteropGenerator; /// /// Extensions for the type. /// -internal static class ModuleDefinitionExtensions +internal static partial class ModuleDefinitionExtensions { /// /// Gets the first type with a given namespace and name from the specified type. @@ -28,15 +29,34 @@ internal static class ModuleDefinitionExtensions /// Thrown if the type couldn't be found. public static TypeDefinition GetType(this ModuleDefinition module, Utf8String ns, Utf8String name) { - foreach (TypeDefinition type in module.TopLevelTypes) + return TryGetType(module, ns, name, out TypeDefinition? type) + ? type + : throw new ArgumentException($"Type with name '{ns}.{name}' not found."); + } + + /// + /// Tries to get the first type with a given namespace and name from the specified type. + /// + /// The input instance. + /// The namespace of the type. + /// The name of the type to get. + /// The resulting type, if found. + /// Whether was found. + public static bool TryGetType(this ModuleDefinition module, Utf8String? ns, Utf8String? name, [NotNullWhen(true)] out TypeDefinition? type) + { + foreach (TypeDefinition item in module.TopLevelTypes) { - if (type.Namespace == ns && type.Name == name) + if (item.Namespace == ns && item.Name == name) { - return type; + type = item; + + return true; } } - throw new ArgumentException($"Type with name '{ns}.{name}' not found."); + type = null; + + return false; } /// diff --git a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs index 43cac0eb8..dc1eaef87 100644 --- a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs @@ -31,12 +31,18 @@ internal static class WindowsRuntimeExtensions /// Whether the module represents a Windows Runtime reference assembly. public bool IsWindowsRuntimeReferenceAssembly => member.HasCustomAttribute(WellKnownMetadataNames.WindowsRuntimeInteropServices, WellKnownMetadataNames.WindowsRuntimeReferenceAssemblyAttribute); + /// + /// Checks whether a (expected to be an ) represents a Windows Runtime component assembly. + /// + /// Whether the module represents a Windows Runtime component assembly. + public bool IsWindowsRuntimeComponentAssembly => member.HasCustomAttribute(WellKnownMetadataNames.WindowsRuntimeInteropServices, WellKnownMetadataNames.WindowsRuntimeComponentAssemblyAttribute); + /// /// Attempts to retrieve the IID from the applied to the specified metadata member. /// /// The instance to use. /// The resulting value, if found. - /// Whether was succesfully retrieved. + /// Whether was successfully retrieved. public bool TryGetGuidAttribute(InteropReferences interopReferences, out Guid iid) { if (member.TryGetCustomAttribute(interopReferences.GuidAttribute, out CustomAttribute? customAttribute)) @@ -1107,4 +1113,9 @@ file static class WellKnownMetadataNames /// The "WindowsRuntimeReferenceAssemblyAttribute" text. /// public static readonly Utf8String WindowsRuntimeReferenceAssemblyAttribute = "WindowsRuntimeReferenceAssemblyAttribute"u8; + + /// + /// The "WindowsRuntimeComponentAssemblyAttribute" text. + /// + public static readonly Utf8String WindowsRuntimeComponentAssemblyAttribute = "WindowsRuntimeComponentAssemblyAttribute"u8; } \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Factories/InteropCustomAttributeFactory.cs b/src/WinRT.Interop.Generator/Factories/InteropCustomAttributeFactory.cs index 949adcfd3..7cc518bc9 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropCustomAttributeFactory.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropCustomAttributeFactory.cs @@ -20,16 +20,18 @@ internal static class InteropCustomAttributeFactory /// Creates a new custom attribute value for (and imports all metadata elements for it). /// /// The type to generate the IID for. + /// The instance to use. /// The instance to use. /// Whether to use Windows.UI.Xaml projections. /// The resulting value. public static CustomAttribute Guid( TypeSignature type, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, bool useWindowsUIXamlProjections) { return Guid( - guid: GuidGenerator.CreateIID(type, interopReferences, useWindowsUIXamlProjections), + guid: GuidGenerator.CreateIID(type, interopDefinitions, interopReferences, useWindowsUIXamlProjections), interopReferences: interopReferences); } diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.DebugRepro.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.DebugRepro.cs index cf9ab4ed1..46190c7fd 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.DebugRepro.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.DebugRepro.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Compression; using System.Linq; @@ -68,6 +69,8 @@ private static string UnpackDebugRepro(string path, CancellationToken token) List referencePaths = []; List implementationPaths = []; string? outputAssemblyPath = null; + string? winRTProjectionAssemblyHashedName = null; + string? winRTComponentAssemblyHashedName = null; // Create another subdirectory for all the input assembly paths. We don't put these in the top level // temporary folder so that the number of files there remains very small. The reason is just to @@ -104,6 +107,16 @@ private static string UnpackDebugRepro(string path, CancellationToken token) { implementationPaths.Add(destinationPath); } + + // Also track the private implementation detail .dll-s (these are also in the set of references) + if (dllEntry.Name == args.WinRTProjectionAssemblyPath) + { + winRTProjectionAssemblyHashedName = destinationPath; + } + else if (args.WinRTComponentAssemblyPath is not null && dllEntry.Name == args.WinRTComponentAssemblyPath) + { + winRTComponentAssemblyHashedName = destinationPath; + } } token.ThrowIfCancellationRequested(); @@ -114,6 +127,8 @@ private static string UnpackDebugRepro(string path, CancellationToken token) ReferenceAssemblyPaths = [.. referencePaths], ImplementationAssemblyPaths = [.. implementationPaths], OutputAssemblyPath = outputAssemblyPath!, + WinRTProjectionAssemblyPath = winRTProjectionAssemblyHashedName!, + WinRTComponentAssemblyPath = winRTComponentAssemblyHashedName, GeneratedAssemblyDirectory = tempDirectory, UseWindowsUIXamlProjections = args.UseWindowsUIXamlProjections, ValidateWinRTRuntimeAssemblyVersion = args.ValidateWinRTRuntimeAssemblyVersion, @@ -175,22 +190,21 @@ private static void SaveDebugRepro(InteropGeneratorArgs args) args.Token.ThrowIfCancellationRequested(); - // Add the output assembly to the temporary directory with a hashed name - string outputAssemblyHashedName = GetHashedFileName(args.OutputAssemblyPath); - string outputAssemblyDestination = Path.Combine(tempDirectory, outputAssemblyHashedName); - - File.Copy(args.OutputAssemblyPath, outputAssemblyDestination, overwrite: true); + // Hash and copy the well known assemblies we use as input + string outputAssemblyHashedName = CopyHashedFileToDirectory(args.OutputAssemblyPath, tempDirectory, originalPaths, args.Token); + string winRTProjectionAssemblyHashedName = CopyHashedFileToDirectory(args.WinRTProjectionAssemblyPath, tempDirectory, originalPaths, args.Token); + string? winRTComponentAssemblyHashedName = CopyHashedFileToDirectory(args.WinRTComponentAssemblyPath, tempDirectory, originalPaths, args.Token); args.Token.ThrowIfCancellationRequested(); - originalPaths.Add(outputAssemblyHashedName, args.OutputAssemblyPath); - // Prepare the .rsp file with all updated arguments string rspText = new InteropGeneratorArgs { ReferenceAssemblyPaths = [.. updatedReferenceDllNames], ImplementationAssemblyPaths = [.. updatedImplementationDllNames], OutputAssemblyPath = outputAssemblyHashedName, + WinRTProjectionAssemblyPath = winRTProjectionAssemblyHashedName, + WinRTComponentAssemblyPath = winRTComponentAssemblyHashedName, GeneratedAssemblyDirectory = args.GeneratedAssemblyDirectory, UseWindowsUIXamlProjections = args.UseWindowsUIXamlProjections, ValidateWinRTRuntimeAssemblyVersion = args.ValidateWinRTRuntimeAssemblyVersion, @@ -279,4 +293,57 @@ private static List CopyHashedFilesToDirectory( return updatedDllNames; } + + /// + /// Copies a specified assembly to a target folder. + /// + /// The input assembly paths. + /// The target directory to copy the assembly to. + /// A dictionary to store the original paths of the copied assemblies. + /// A cancellation token to monitor for cancellation requests. + /// The hashed filename. + [return: NotNullIfNotNull(nameof(assemblyPath))] + private static string? CopyHashedFileToDirectory( + string? assemblyPath, + string destinationDirectory, + Dictionary originalPaths, + CancellationToken token) + { + if (assemblyPath is null) + { + return null; + } + + string hashedName = GetHashedFileName(assemblyPath); + + // Special case for private implementation detail assemblies (e.g. 'WinRT.Projection.dll') that are + // both passed via the reference set, but also explicitly as separate properties. In that case, we + // expect that those should already be in the original paths at this point. So we validate that + // the path actually matches, and simply do nothing if that's the case, as this is intended. + if (originalPaths.TryGetValue(hashedName, out string? originalPath) && originalPath == assemblyPath) + { + return hashedName; + } + + // If we get to this point, it means that either a private implementation assembly was passed with a + // different path than the one provided to the reference set, which should never happen (it's invalid). + if (originalPaths.ContainsKey(hashedName)) + { + string fileName = Path.GetFileName(Path.Normalize(assemblyPath)); + + throw WellKnownInteropExceptions.ReservedDllOriginalPathMismatchFromDebugRepro(fileName); + } + + string destinationPath = Path.Combine(destinationDirectory, hashedName); + + // After validating that the file is unique and should be copied, we can safely do that. We move + // this operation to ensure we don't accidentally end up with duplicated .dll-s in the debug repro. + File.Copy(assemblyPath, destinationPath, overwrite: true); + + token.ThrowIfCancellationRequested(); + + originalPaths.Add(hashedName, assemblyPath); + + return hashedName; + } } \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs index e289bff12..5989a9b53 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs @@ -40,6 +40,10 @@ private static InteropGeneratorDiscoveryState Discover(InteropGeneratorArgs args // No additional parameters will be passed to later steps: all the info is in this object. InteropGeneratorDiscoveryState discoveryState = new() { AssemblyResolver = pathAssemblyResolver }; + // First, load the special 'WinRT.Projection.dll' and 'WinRT.Component.dll' modules (the latter is optional). + // These are necessary for surfacing some information needed to generate code, that is not present otherwise. + LoadWinRTModules(args, discoveryState); + try { // Load and process all modules, potentially in parallel @@ -75,6 +79,29 @@ private static InteropGeneratorDiscoveryState Discover(InteropGeneratorArgs args return discoveryState; } + /// + /// Loads the special WinRT module definitions. + /// + /// The arguments for this invocation. + /// The discovery state for this invocation. + private static void LoadWinRTModules(InteropGeneratorArgs args, InteropGeneratorDiscoveryState discoveryState) + { + // Load the 'WinRT.Projection.dll' module, this should always be available + ModuleDefinition winRTProjectionModule = ModuleDefinition.FromFile(args.WinRTProjectionAssemblyPath, ((PathAssemblyResolver)discoveryState.AssemblyResolver).ReaderParameters); + + discoveryState.TrackWinRTProjectionModuleDefinition(winRTProjectionModule); + + args.Token.ThrowIfCancellationRequested(); + + // Load the 'WinRT.Component.dll' module, if available + if (args.WinRTComponentAssemblyPath is not null) + { + ModuleDefinition winRTComponentModule = ModuleDefinition.FromFile(args.WinRTComponentAssemblyPath, ((PathAssemblyResolver)discoveryState.AssemblyResolver).ReaderParameters); + + discoveryState.TrackWinRTComponentModuleDefinition(winRTComponentModule); + } + } + /// /// Loads and processes a module definition. /// @@ -86,6 +113,33 @@ private static void LoadAndProcessModule( InteropGeneratorDiscoveryState discoveryState, string path) { + ReadOnlySpan fileName = Path.GetFileName(path.AsSpan()); + + // Validate that the two possible private implementation detail .dll-s we expect have a matching path. These are: + // - 'WinRT.Projection.dll': the generated merged projection assembly. + // - 'WinRT.Component.dll': the optional generated merged component assembly. + if ((fileName.SequenceEqual(InteropNames.WindowsRuntimeProjectionDllName) && path != args.WinRTProjectionAssemblyPath) || + (fileName.SequenceEqual(InteropNames.WindowsRuntimeComponentDllName) && path != args.WinRTComponentAssemblyPath)) + { + throw WellKnownInteropExceptions.ReservedDllOriginalPathMismatch(fileName.ToString()); + } + + // If the current module is one of those two .dll-s, we just skip it. They will be loaded separately (see above). + // However since they're also passed in the reference set (as they need to be referenced by the app directly), + // they will also show up here. This is intended, and it simplifies the targets (no need for them to filter items). + if (fileName.SequenceEqual(InteropNames.WindowsRuntimeProjectionDllName) || + fileName.SequenceEqual(InteropNames.WindowsRuntimeComponentDllName)) + { + return; + } + + // Validate that the reserved 'WinRT.Interop.dll' is not passed as input. This is the .dll that this tool is generating, + // so for it to already exist and be passed as input would always be invalid (and would indicate some kind of build issue). + if (fileName.SequenceEqual(InteropNames.WindowsRuntimeInteropDllName)) + { + throw WellKnownInteropExceptions.ReservedDllNameReferenceError(fileName.ToString()); + } + ModuleDefinition module; // Try to load the .dll at the current path diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index 629f286c7..30def2216 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -45,7 +45,10 @@ private static void Emit(InteropGeneratorArgs args, InteropGeneratorDiscoverySta // Setup the well known items to use when emitting code InteropReferences interopReferences = new(module.CorLibTypeFactory, windowsRuntimeModule, windowsFoundationModule); - InteropDefinitions interopDefinitions = new(interopReferences); + InteropDefinitions interopDefinitions = new( + interopReferences: interopReferences, + windowsRuntimeProjectionModule: discoveryState.WinRTProjectionModuleDefinition!, + windowsRuntimeComponentModule: discoveryState.WinRTComponentModuleDefinition); args.Token.ThrowIfCancellationRequested(); @@ -171,7 +174,7 @@ private static void Emit(InteropGeneratorArgs args, InteropGeneratorDiscoverySta args.Token.ThrowIfCancellationRequested(); // Add all dynamic type map entries for custom-mapped types - DefineDynamicCustomMappedTypeMapEntries(args, interopReferences, module); + DefineDynamicCustomMappedTypeMapEntries(args, interopDefinitions, interopReferences, module); args.Token.ThrowIfCancellationRequested(); @@ -238,7 +241,7 @@ private static ModuleDefinition DefineInteropModule( try { // Create the module for the 'WinRT.Interop.dll' assembly, where we'll add all generated types to - ModuleDefinition winRTInteropModule = new(InteropNames.InteropDllNameUtf8, assemblyModule.OriginalTargetRuntime.GetDefaultCorLib()) + ModuleDefinition winRTInteropModule = new(InteropNames.WindowsRuntimeInteropDllNameUtf8, assemblyModule.OriginalTargetRuntime.GetDefaultCorLib()) { // Create and set a metadata resolver from the assembly resolver that we created during the discovery phase (used for auto-import) MetadataResolver = new DefaultMetadataResolver(discoveryState.AssemblyResolver), @@ -250,7 +253,7 @@ private static ModuleDefinition DefineInteropModule( // Also create a containing assembly for it (needed for the emit phase). We don't actually need the assembly // ourselves, but creating it and adding the module will update the declaring assembly for types added to it. - _ = new AssemblyDefinition(InteropNames.InteropAssemblyNameUtf8, assemblyModule.Assembly?.Version ?? new Version(0, 0, 0, 0)) + _ = new AssemblyDefinition(InteropNames.WindowsRuntimeInteropAssemblyNameUtf8, assemblyModule.Assembly?.Version ?? new Version(0, 0, 0, 0)) { Modules = { winRTInteropModule } }; @@ -525,6 +528,7 @@ private static void DefineIEnumeratorTypes( InteropTypeDefinitionBuilder.IEnumerator1.InterfaceImpl( enumeratorType: typeSignature, iteratorMethodsType: iteratorMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -650,6 +654,7 @@ private static void DefineIEnumerableTypes( InteropTypeDefinitionBuilder.IEnumerable1.InterfaceImpl( enumerableType: typeSignature, iterableMethodsType: iterableMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -777,6 +782,7 @@ private static void DefineIReadOnlyListTypes( InteropTypeDefinitionBuilder.IReadOnlyList1.InterfaceImpl( readOnlyListType: typeSignature, readOnlyListMethodsType: readOnlyListMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -912,6 +918,7 @@ private static void DefineIListTypes( InteropTypeDefinitionBuilder.IList1.InterfaceImpl( listType: typeSignature, listMethodsType: listMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1040,6 +1047,7 @@ private static void DefineIReadOnlyDictionaryTypes( InteropTypeDefinitionBuilder.IReadOnlyDictionary2.InterfaceImpl( readOnlyDictionaryType: typeSignature, readOnlyDictionaryMethodsType: readOnlyDictionaryMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1176,6 +1184,7 @@ private static void DefineIDictionaryTypes( InteropTypeDefinitionBuilder.IDictionary2.InterfaceImpl( dictionaryType: typeSignature, dictionaryMethodsType: dictionaryMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1400,6 +1409,7 @@ private static void DefineIMapChangedEventArgsTypes( InteropTypeDefinitionBuilder.IMapChangedEventArgs1.InterfaceImpl( argsType: typeSignature, argsMethodsType: argsMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1517,6 +1527,7 @@ private static void DefineIObservableVectorTypes( InteropTypeDefinitionBuilder.IObservableVector1.InterfaceImpl( vectorType: typeSignature, vectorMethodsType: methodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1634,6 +1645,7 @@ private static void DefineIObservableMapTypes( InteropTypeDefinitionBuilder.IObservableMap2.InterfaceImpl( mapType: typeSignature, mapMethodsType: methodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1744,6 +1756,7 @@ private static void DefineIAsyncActionWithProgressTypes( InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.InterfaceImpl( actionType: typeSignature, actionMethodsType: actionMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1854,6 +1867,7 @@ private static void DefineIAsyncOperationTypes( InteropTypeDefinitionBuilder.IAsyncOperation1.InterfaceImpl( operationType: typeSignature, operationMethodsType: operationMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1964,6 +1978,7 @@ private static void DefineIAsyncOperationWithProgressTypes( InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.InterfaceImpl( operationType: typeSignature, operationMethodsType: operationMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -2514,10 +2529,12 @@ private static void DefineDynamicImplementationDetailTypes(InteropDefinitions in /// Defines the dynamic type map entries for custom-mapped types. /// /// + /// The instance to use. /// The instance to use. /// The interop module being built. private static void DefineDynamicCustomMappedTypeMapEntries( InteropGeneratorArgs args, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module) { @@ -2525,6 +2542,7 @@ private static void DefineDynamicCustomMappedTypeMapEntries( { DynamicCustomMappedTypeMapEntriesBuilder.AssemblyAttributes( args: args, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module); } @@ -2589,7 +2607,7 @@ private static void EmitMetadataAssemblyAttributes(InteropReferences interopRefe /// The module to write to disk. private static void WriteInteropModuleToDisk(InteropGeneratorArgs args, ModuleDefinition module) { - string winRTInteropAssemblyPath = Path.Combine(args.GeneratedAssemblyDirectory, InteropNames.InteropDllName); + string winRTInteropAssemblyPath = Path.Combine(args.GeneratedAssemblyDirectory, InteropNames.WindowsRuntimeInteropDllName); try { diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.cs index fb787250b..05471dccb 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.cs @@ -115,6 +115,6 @@ public static void Run([Argument] string inputFilePath, CancellationToken token) } // Notify the user that generation was successful - ConsoleApp.Log($"Interop code generated -> {Path.Combine(args.GeneratedAssemblyDirectory, InteropNames.InteropDllName)}"); + ConsoleApp.Log($"Interop code generated -> {Path.Combine(args.GeneratedAssemblyDirectory, InteropNames.WindowsRuntimeInteropDllName)}"); } } \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.Formatting.cs b/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.Formatting.cs index c0ac96f03..85d79fe34 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.Formatting.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.Formatting.cs @@ -28,6 +28,17 @@ public string FormatToResponseFile() _ = builder.Append(' '); _ = builder.AppendLine(OutputAssemblyPath); + _ = builder.Append(GetCommandLineArgumentName(nameof(WinRTProjectionAssemblyPath))); + _ = builder.Append(' '); + _ = builder.AppendLine(WinRTProjectionAssemblyPath); + + if (WinRTComponentAssemblyPath is not null) + { + _ = builder.Append(GetCommandLineArgumentName(nameof(WinRTComponentAssemblyPath))); + _ = builder.Append(' '); + _ = builder.AppendLine(WinRTComponentAssemblyPath); + } + _ = builder.Append(GetCommandLineArgumentName(nameof(GeneratedAssemblyDirectory))); _ = builder.Append(' '); _ = builder.AppendLine(GeneratedAssemblyDirectory); diff --git a/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.Parsing.cs b/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.Parsing.cs index ed1f2507e..9ebe6070e 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.Parsing.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.Parsing.cs @@ -100,6 +100,8 @@ private static InteropGeneratorArgs ParseFromResponseFile(string[] lines, Cancel ReferenceAssemblyPaths = GetStringArrayArgument(argsMap, nameof(ReferenceAssemblyPaths)), ImplementationAssemblyPaths = GetStringArrayArgument(argsMap, nameof(ImplementationAssemblyPaths)), OutputAssemblyPath = GetStringArgument(argsMap, nameof(OutputAssemblyPath)), + WinRTProjectionAssemblyPath = GetStringArgument(argsMap, nameof(WinRTProjectionAssemblyPath)), + WinRTComponentAssemblyPath = GetNullableStringArgument(argsMap, nameof(WinRTComponentAssemblyPath)), GeneratedAssemblyDirectory = GetStringArgument(argsMap, nameof(GeneratedAssemblyDirectory)), UseWindowsUIXamlProjections = GetBooleanArgument(argsMap, nameof(UseWindowsUIXamlProjections)), ValidateWinRTRuntimeAssemblyVersion = GetBooleanArgument(argsMap, nameof(ValidateWinRTRuntimeAssemblyVersion)), diff --git a/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.cs b/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.cs index f0be421cd..9f2045709 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGeneratorArgs.cs @@ -23,6 +23,14 @@ internal sealed partial class InteropGeneratorArgs [CommandLineArgumentName("--output-assembly-path")] public required string OutputAssemblyPath { get; init; } + /// Gets the path of the WinRT.Projection.dll assembly. + [CommandLineArgumentName("--winrt-projection-assembly-path")] + public required string WinRTProjectionAssemblyPath { get; init; } + + /// Gets the path of the WinRT.Component.dll assembly, if available. + [CommandLineArgumentName("--winrt-component-assembly-path")] + public string? WinRTComponentAssemblyPath { get; init; } + /// Gets the directory to use to place the generated assembly. [CommandLineArgumentName("--generated-assembly-directory")] public required string GeneratedAssemblyDirectory { get; init; } diff --git a/src/WinRT.Interop.Generator/Generation/InteropGeneratorDiscoveryState.cs b/src/WinRT.Interop.Generator/Generation/InteropGeneratorDiscoveryState.cs index 5fbfdabe2..99e1b3125 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGeneratorDiscoveryState.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGeneratorDiscoveryState.cs @@ -3,6 +3,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using AsmResolver.DotNet; using AsmResolver.DotNet.Signatures; using WindowsRuntime.InteropGenerator.Errors; @@ -18,6 +19,12 @@ internal sealed class InteropGeneratorDiscoveryState /// Backing field for . private readonly ConcurrentDictionary _moduleDefinitions = []; + /// Backing field for . + private ModuleDefinition? _winRTProjectionModuleDefinition; + + /// Backing field for . + private ModuleDefinition? _winRTComponentModuleDefinition; + /// Backing field for . private readonly ConcurrentDictionary _typeHierarchyEntries = []; @@ -109,6 +116,16 @@ internal sealed class InteropGeneratorDiscoveryState /// public IReadOnlyDictionary ModuleDefinitions => _moduleDefinitions; + /// + /// Gets the for WinRT.Projection.dll. + /// + public ModuleDefinition? WinRTProjectionModuleDefinition => _winRTProjectionModuleDefinition; + + /// + /// Gets the for WinRT.Component.dll. + /// + public ModuleDefinition? WinRTComponentModuleDefinition => _winRTComponentModuleDefinition; + /// /// Gets the type hierarchy entries. /// @@ -221,6 +238,30 @@ public void TrackModuleDefinition(string path, ModuleDefinition module) _ = _moduleDefinitions.TryAdd(path, module); } + /// + /// Tracks the WinRT.Projection.dll loaded module definition. + /// + /// The loaded module. + [MemberNotNull(nameof(_winRTProjectionModuleDefinition))] + public void TrackWinRTProjectionModuleDefinition(ModuleDefinition module) + { + ThrowIfReadOnly(); + + _winRTProjectionModuleDefinition = module; + } + + /// + /// Tracks the WinRT.Component.dll loaded module definition. + /// + /// The loaded module. + [MemberNotNull(nameof(_winRTComponentModuleDefinition))] + public void TrackWinRTComponentModuleDefinition(ModuleDefinition module) + { + ThrowIfReadOnly(); + + _winRTComponentModuleDefinition = module; + } + /// /// Tracks a pair of runtime class names for the type hierarchy. /// diff --git a/src/WinRT.Interop.Generator/Helpers/GuidGenerator.cs b/src/WinRT.Interop.Generator/Helpers/GuidGenerator.cs index eb723672e..851fcc888 100644 --- a/src/WinRT.Interop.Generator/Helpers/GuidGenerator.cs +++ b/src/WinRT.Interop.Generator/Helpers/GuidGenerator.cs @@ -6,7 +6,6 @@ using System.Diagnostics; using System.Security.Cryptography; using System.Text; -using AsmResolver.DotNet; using AsmResolver.DotNet.Signatures; using WindowsRuntime.InteropGenerator.References; @@ -27,56 +26,22 @@ internal static class GuidGenerator /// Generates the IID for the specified type by computing its Windows Runtime signature and deriving an IID from that signature. /// /// The to generate the IID for. + /// The instance to use. /// The instance to use. /// Whether to use Windows.UI.Xaml projections. /// The resulting IID for . - public static Guid CreateIID(TypeSignature type, InteropReferences interopReferences, bool useWindowsUIXamlProjections) + public static Guid CreateIID( + TypeSignature type, + InteropDefinitions interopDefinitions, + InteropReferences interopReferences, + bool useWindowsUIXamlProjections) { - string signature = SignatureGenerator.GetSignature(type, interopReferences, useWindowsUIXamlProjections); + string signature = SignatureGenerator.GetSignature(type, interopDefinitions, interopReferences, useWindowsUIXamlProjections); Guid guid = CreateGuidFromSignature(signature); return guid; } - /// - /// Tries to resolve the IID for the specified type signature by checking well-known Windows Runtime - /// interfaces and, if necessary, the type's . - /// - /// The type descriptor to try to get the IID for. - /// Whether to use Windows.UI.Xaml projections. - /// The instance to use. - /// The resulting value, if found. - /// Whether was succesfully retrieved. - public static bool TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( - ITypeDescriptor type, - bool useWindowsUIXamlProjections, - InteropReferences interopReferences, - out Guid iid) - { - // First try to get the IID from the custom-mapped types mapping - if (WellKnownInterfaceIIDs.TryGetGUID( - interfaceType: type, - useWindowsUIXamlProjections: useWindowsUIXamlProjections, - interopReferences: interopReferences, - guid: out iid)) - { - return true; - } - - if (type.Resolve() is TypeDefinition typeDefinition) - { - // If the type was a normal projected type, then try to resolve the IID from the '[Guid]' attribute - if (typeDefinition.TryGetGuidAttribute(interopReferences, out iid)) - { - return true; - } - } - - iid = Guid.Empty; - - return false; - } - /// /// Encodes a from a 16-byte sequence following RFC 4122 rules. /// Adjusts byte order for little-endian systems and sets version and variant bits. diff --git a/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.Projections.cs b/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.Projections.cs index c875a115c..e5126573e 100644 --- a/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.Projections.cs +++ b/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.Projections.cs @@ -18,15 +18,21 @@ internal partial class SignatureGenerator /// Tries to get the signature of a constructed generic type. /// /// + /// /// /// /// The resulting signature, or in case of failures. - private static string? GenericInstance(GenericInstanceTypeSignature typeSignature, InteropReferences interopReferences, bool useWindowsUIXamlProjections) + private static string? GenericInstance( + GenericInstanceTypeSignature typeSignature, + InteropDefinitions interopDefinitions, + InteropReferences interopReferences, + bool useWindowsUIXamlProjections) { // If we fail to get the IID of the generic interface, we can't do anything else - if (!GuidGenerator.TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( + if (!TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( type: typeSignature.GenericType, useWindowsUIXamlProjections: useWindowsUIXamlProjections, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, iid: out Guid interfaceIid)) { @@ -44,7 +50,7 @@ internal partial class SignatureGenerator foreach (TypeSignature argumentSignature in typeSignature.TypeArguments) { handler.AppendFormatted(';'); - handler.AppendFormatted(GetSignature(argumentSignature, interopReferences, useWindowsUIXamlProjections)); + handler.AppendFormatted(GetSignature(argumentSignature, interopDefinitions, interopReferences, useWindowsUIXamlProjections)); } handler.AppendFormatted(')'); @@ -77,12 +83,14 @@ internal partial class SignatureGenerator /// /// The full name of the value type. /// The to generate the signature for. + /// /// /// /// The resulting signature, or in case of failures. private static string? ValueType( string typeFullName, TypeDefinition typeDefinition, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, bool useWindowsUIXamlProjections) { @@ -114,7 +122,7 @@ internal partial class SignatureGenerator } handler.AppendFormatted(';'); - handler.AppendFormatted(GetSignature(fieldSignature, interopReferences, useWindowsUIXamlProjections)); + handler.AppendFormatted(GetSignature(fieldSignature, interopDefinitions, interopReferences, useWindowsUIXamlProjections)); } handler.AppendFormatted(')'); @@ -126,14 +134,20 @@ internal partial class SignatureGenerator /// Tries to get the signature of a delegate type. /// /// The to generate the signature for. + /// /// /// - private static string? Delegate(TypeDefinition typeDefinition, InteropReferences interopReferences, bool useWindowsUIXamlProjections) + private static string? Delegate( + TypeDefinition typeDefinition, + InteropDefinitions interopDefinitions, + InteropReferences interopReferences, + bool useWindowsUIXamlProjections) { // Just like for generic instantiations, we need to resolve the IID for the type first - if (!GuidGenerator.TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( + if (TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( type: typeDefinition, useWindowsUIXamlProjections: useWindowsUIXamlProjections, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, iid: out Guid iid)) { @@ -149,25 +163,28 @@ internal partial class SignatureGenerator /// /// The full name of the class type. /// The to generate the signature for. + /// /// /// /// The resulting signature, or in case of failures. private static string? Class( string typeFullName, TypeDefinition typeDefinition, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, bool useWindowsUIXamlProjections) { // If we can resolve the default interface type from the projected runtime class, use it - if (TryGetDefaultInterfaceFromAttribute(typeDefinition, interopReferences, out TypeSignature? defaultInterface)) + if (TryGetDefaultInterfaceFromAttribute(typeDefinition, interopDefinitions, interopReferences, out TypeSignature? defaultInterface)) { - return $"rc({typeFullName};{GetSignature(defaultInterface, interopReferences, useWindowsUIXamlProjections)})"; + return $"rc({typeFullName};{GetSignature(defaultInterface, interopDefinitions, interopReferences, useWindowsUIXamlProjections)})"; } // Otherwise, get the IID from the type definition and use it - if (!GuidGenerator.TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( + if (!TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( type: typeDefinition, useWindowsUIXamlProjections: useWindowsUIXamlProjections, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, iid: out Guid iid)) { @@ -181,14 +198,20 @@ internal partial class SignatureGenerator /// Tries to get the signature of an interface type. /// /// The to generate the signature for. + /// /// /// - private static string? Interface(TypeDefinition typeDefinition, InteropReferences interopReferences, bool useWindowsUIXamlProjections) + private static string? Interface( + TypeDefinition typeDefinition, + InteropDefinitions interopDefinitions, + InteropReferences interopReferences, + bool useWindowsUIXamlProjections) { // For all interface types, we should always be able to resolve their IID - if (!GuidGenerator.TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( + if (!TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( type: typeDefinition, useWindowsUIXamlProjections: useWindowsUIXamlProjections, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, iid: out Guid iid)) { @@ -203,12 +226,14 @@ internal partial class SignatureGenerator /// /// /// The to generate the signature for. + /// /// /// /// The resulting signature, or in case of failures. private static string? Box( BoxedTypeSignature typeSignature, TypeDefinition typeDefinition, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, bool useWindowsUIXamlProjections) { @@ -227,17 +252,22 @@ internal partial class SignatureGenerator guid: out Guid iid); // Construct the signature for the boxed delegate (the base type will be the possibly constructed delegate) - return $"pinterface({{{iid}}};{GetSignature(typeSignature.BaseType, interopReferences, useWindowsUIXamlProjections)})"; + return $"pinterface({{{iid}}};{GetSignature(typeSignature.BaseType, interopDefinitions, interopReferences, useWindowsUIXamlProjections)})"; } /// /// Tries to get the signature of an array type. /// /// + /// /// /// - private static string? Array(SzArrayTypeSignature typeSignature, InteropReferences interopReferences, bool useWindowsUIXamlProjections) + private static string? Array( + SzArrayTypeSignature typeSignature, + InteropDefinitions interopDefinitions, + InteropReferences interopReferences, + bool useWindowsUIXamlProjections) { - return $"pinterface({{61c17707-2d65-11e0-9ae8-d48564015472}};{GetSignature(typeSignature.BaseType, interopReferences, useWindowsUIXamlProjections)})"; + return $"pinterface({{61c17707-2d65-11e0-9ae8-d48564015472}};{GetSignature(typeSignature.BaseType, interopDefinitions, interopReferences, useWindowsUIXamlProjections)})"; } } diff --git a/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.cs b/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.cs index 14f70564b..b6b66bc1c 100644 --- a/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.cs +++ b/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System; using System.Diagnostics.CodeAnalysis; using AsmResolver.DotNet; using AsmResolver.DotNet.Signatures; @@ -21,11 +22,13 @@ internal static partial class SignatureGenerator /// Generates the Windows Runtime signature for the specified type. /// /// The to generate the signature for. + /// The instance to use. /// The instance to use. /// Whether to use Windows.UI.Xaml projections. /// The resulting signature for . public static string GetSignature( TypeSignature type, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, bool useWindowsUIXamlProjections) { @@ -66,15 +69,15 @@ public static string GetSignature( ElementType.Object => ObjectSignature, ElementType.String => StringSignature, ElementType.Type => TypeSignature, - ElementType.GenericInst => GenericInstance((GenericInstanceTypeSignature)type, interopReferences, useWindowsUIXamlProjections), + ElementType.GenericInst => GenericInstance((GenericInstanceTypeSignature)type, interopDefinitions, interopReferences, useWindowsUIXamlProjections), ElementType.ValueType when typeDefinition.IsClass && typeDefinition.IsEnum => Enum(typeFullName, typeDefinition, interopReferences), ElementType.ValueType when typeDefinition.IsClass && type.IsTypeOfGuid(interopReferences) => GuidSignature, - ElementType.ValueType when typeDefinition.IsClass => ValueType(typeFullName, typeDefinition, interopReferences, useWindowsUIXamlProjections), - ElementType.Class when typeDefinition.IsClass && typeDefinition.IsDelegate => Delegate(typeDefinition, interopReferences, useWindowsUIXamlProjections), - ElementType.Class when typeDefinition.IsClass => Class(typeFullName, typeDefinition, interopReferences, useWindowsUIXamlProjections), - ElementType.Class when typeDefinition.IsInterface => Interface(typeDefinition, interopReferences, useWindowsUIXamlProjections), - ElementType.Boxed => Box((BoxedTypeSignature)type, typeDefinition, interopReferences, useWindowsUIXamlProjections), - ElementType.SzArray => Array((SzArrayTypeSignature)type, interopReferences, useWindowsUIXamlProjections), + ElementType.ValueType when typeDefinition.IsClass => ValueType(typeFullName, typeDefinition, interopDefinitions, interopReferences, useWindowsUIXamlProjections), + ElementType.Class when typeDefinition.IsClass && typeDefinition.IsDelegate => Delegate(typeDefinition, interopDefinitions, interopReferences, useWindowsUIXamlProjections), + ElementType.Class when typeDefinition.IsClass => Class(typeFullName, typeDefinition, interopDefinitions, interopReferences, useWindowsUIXamlProjections), + ElementType.Class when typeDefinition.IsInterface => Interface(typeDefinition, interopDefinitions, interopReferences, useWindowsUIXamlProjections), + ElementType.Boxed => Box((BoxedTypeSignature)type, typeDefinition, interopDefinitions, interopReferences, useWindowsUIXamlProjections), + ElementType.SzArray => Array((SzArrayTypeSignature)type, interopDefinitions, interopReferences, useWindowsUIXamlProjections), _ => null }; @@ -92,20 +95,107 @@ public static string GetSignature( throw WellKnownInteropExceptions.TypeSignatureGenerationError(type); } + /// + /// Tries to resolve the IID for the specified type signature by checking well-known Windows Runtime + /// interfaces and, if necessary, the type's . + /// + /// The type descriptor to try to get the IID for. + /// Whether to use Windows.UI.Xaml projections. + /// The instance to use. + /// The instance to use. + /// The resulting value, if found. + /// Whether was successfully retrieved. + private static bool TryGetIIDFromWellKnownInterfaceIIDsOrAttribute( + ITypeDescriptor type, + bool useWindowsUIXamlProjections, + InteropDefinitions interopDefinitions, + InteropReferences interopReferences, + out Guid iid) + { + // First try to get the IID from the custom-mapped types mapping + if (WellKnownInterfaceIIDs.TryGetGUID( + interfaceType: type, + useWindowsUIXamlProjections: useWindowsUIXamlProjections, + interopReferences: interopReferences, + guid: out iid)) + { + return true; + } + + // If we can resolve the type, try to retrieve the IID from the '[Guid]' attribute on it + if (type.Resolve() is TypeDefinition typeDefinition) + { + return TryGetIIDFromAttribute( + typeDefinition, + interopDefinitions, + interopReferences, + out iid); + } + + iid = Guid.Empty; + + return false; + } + + /// + /// Attempts to retrieve the IID for the specified type by checking the + /// attribute applied to it, if presen. The type is assumed to be some projected Windows Runtime interface or delegate type. + /// + /// The type descriptor to try to get the IID for. + /// The instance to use. + /// The instance to use. + /// The resulting value, if found. + /// Whether was successfully retrieved. + private static bool TryGetIIDFromAttribute( + TypeDefinition type, + InteropDefinitions interopDefinitions, + InteropReferences interopReferences, + out Guid iid) + { + // If the type had the '[Guid]' attribute directly on it, get it from there (this is the case for interfaces) + if (type.TryGetGuidAttribute(interopReferences, out iid)) + { + return true; + } + + // For delegates, try to get the projected type from the projection .dll, as they will have the '[Guid]' attribute on them. + // These are only needed to generate signatures, so we hide them from the reference assemblies, as they're not useful there. + if (type.IsDelegate && + interopDefinitions.WindowsRuntimeProjectionModule.GetTopLevelTypesLookup().TryGetValue((type.Namespace, type.Name), out TypeDefinition? projectedType)) + { + return projectedType.TryGetGuidAttribute(interopReferences, out iid); + } + + iid = Guid.Empty; + + return false; + } + /// /// Attempts to retrieve the default interface signature from the [WindowsRuntimeDefaultInterface] /// attribute applied to the specified type, which is assumed to be some projected Windows Runtime class. /// /// The type definition to inspect for the default interface attribute. + /// The instance to use. /// The instance to use. /// The instance for the default interface for , if found. /// Whether was successfully retrieved. private static bool TryGetDefaultInterfaceFromAttribute( TypeDefinition type, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, [NotNullWhen(true)] out TypeSignature? defaultInterface) { - if (type.TryGetCustomAttribute(interopReferences.WindowsRuntimeDefaultInterfaceAttribute, out CustomAttribute? customAttribute)) + // Tries to get the projected type from the projection .dll, as it will have the attribute + if (!interopDefinitions.WindowsRuntimeProjectionModule.GetTopLevelTypesLookup().TryGetValue((type.Namespace, type.Name), out TypeDefinition? projectedType)) + { + defaultInterface = null; + + return false; + } + + // Try to lookup '[WindowsRuntimeDefaultInterface]' from the projected type, if we found it + if (projectedType.TryGetCustomAttribute(interopReferences.WindowsRuntimeDefaultInterfaceAttribute, out CustomAttribute? customAttribute)) { if (customAttribute.Signature is { FixedArguments: [{ Element: TypeSignature signature }, ..] }) { diff --git a/src/WinRT.Interop.Generator/References/InteropDefinitions.cs b/src/WinRT.Interop.Generator/References/InteropDefinitions.cs index 4fd303183..613f88b83 100644 --- a/src/WinRT.Interop.Generator/References/InteropDefinitions.cs +++ b/src/WinRT.Interop.Generator/References/InteropDefinitions.cs @@ -32,13 +32,31 @@ internal sealed class InteropDefinitions /// Creates a new instance. /// /// The instance to use. - public InteropDefinitions(InteropReferences interopReferences) + /// The for the Windows Runtime projection assembly (i.e. WinRT.Projection.dll). + /// The for the Windows Runtime component assembly (i.e. WinRT.Component.dll). + public InteropDefinitions( + InteropReferences interopReferences, + ModuleDefinition windowsRuntimeProjectionModule, + ModuleDefinition? windowsRuntimeComponentModule) { _interopReferences = interopReferences; _userDefinedInterfaceEntries = []; _szArrayInterfaceEntries = []; + + WindowsRuntimeProjectionModule = windowsRuntimeProjectionModule; + WindowsRuntimeComponentModule = windowsRuntimeComponentModule; } + /// + /// Gets the for the Windows Runtime projection assembly (i.e. WinRT.Projection.dll). + /// + public ModuleDefinition WindowsRuntimeProjectionModule { get; } + + /// + /// Gets the for the Windows Runtime component assembly (i.e. WinRT.Component.dll). + /// + public ModuleDefinition? WindowsRuntimeComponentModule { get; } + /// /// Gets the for the IgnoresAccessChecksToAttribute type. /// diff --git a/src/WinRT.Interop.Generator/References/InteropNames.cs b/src/WinRT.Interop.Generator/References/InteropNames.cs index 3baba1809..eff666568 100644 --- a/src/WinRT.Interop.Generator/References/InteropNames.cs +++ b/src/WinRT.Interop.Generator/References/InteropNames.cs @@ -11,29 +11,39 @@ namespace WindowsRuntime.InteropGenerator.References; internal static class InteropNames { /// - /// The name of the generated interop .dll. + /// The name of the generated interop .dll (i.e. WinRT.Interop.dll). /// - public const string InteropDllName = "WinRT.Interop.dll"; + public const string WindowsRuntimeInteropDllName = "WinRT.Interop.dll"; /// - /// The name of the generated interop assembly. + /// The name of the generated projection .dll (i.e. WinRT.Projection.dll). /// - public static ReadOnlySpan InteropAssemblyNameUtf8 => "WinRT.Interop"u8; + public const string WindowsRuntimeProjectionDllName = "WinRT.Projection.dll"; /// - /// The name of the generated interop .dll. + /// The name of the generated component .dll (i.e. WinRT.Component.dll). /// - public static ReadOnlySpan InteropDllNameUtf8 => "WinRT.Interop.dll"u8; + public const string WindowsRuntimeComponentDllName = "WinRT.Component.dll"; /// - /// The name of the WinRT runtime .dll. + /// The name of the generated interop assembly (i.e. WinRT.Interop.dll). /// - public static ReadOnlySpan WinRTRuntimeDllNameUtf8 => "WinRT.Runtime.dll"u8; + public static ReadOnlySpan WindowsRuntimeInteropAssemblyNameUtf8 => "WinRT.Interop"u8; /// - /// The current name of the WinRT runtime .dll. + /// The name of the generated interop .dll (i.e. WinRT.Interop.dll). /// - public static ReadOnlySpan WinRTRuntime2DllNameUtf8 => "WinRT.Runtime2.dll"u8; + public static ReadOnlySpan WindowsRuntimeInteropDllNameUtf8 => "WinRT.Interop.dll"u8; + + /// + /// The name of the Windows Runtime .dll (i.e. WinRT.Runtime.dll). + /// + public static ReadOnlySpan WindowsRuntimeDllNameUtf8 => "WinRT.Runtime.dll"u8; + + /// + /// The current name of the Windows Runtime .dll (i.e. WinRT.Runtime2.dll). + /// + public static ReadOnlySpan WindowsRuntime2DllNameUtf8 => "WinRT.Runtime2.dll"u8; /// /// The name of the Windows SDK projections .dll. diff --git a/src/WinRT.Interop.Generator/References/InteropReferences.cs b/src/WinRT.Interop.Generator/References/InteropReferences.cs index 17c82b425..c2ccd6f84 100644 --- a/src/WinRT.Interop.Generator/References/InteropReferences.cs +++ b/src/WinRT.Interop.Generator/References/InteropReferences.cs @@ -21,7 +21,7 @@ internal sealed class InteropReferences private readonly CorLibTypeFactory _corLibTypeFactory; /// - /// The for the Windows Runtime assembly. + /// The for the Windows Runtime assembly (i.e. WinRT.Runtime.dll). /// private readonly IResolutionScope _windowsRuntimeModule; @@ -34,7 +34,7 @@ internal sealed class InteropReferences /// Creates a new instance. /// /// The currently in use. - /// The for the Windows Runtime assembly. + /// The for the Windows Runtime assembly (i.e. WinRT.Runtime.dll). /// The for the Windows SDK projection assembly. public InteropReferences( CorLibTypeFactory corLibTypeFactory, @@ -103,7 +103,7 @@ public InteropReferences( public CorLibTypeSignature Object => _corLibTypeFactory.Object; /// - /// Gets the for the Windows Runtime assembly. + /// Gets the for the Windows Runtime assembly (i.e. WinRT.Runtime.dll). /// public IResolutionScope WindowsRuntimeModule => _windowsRuntimeModule; diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 25461026e..92f218ed8 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -4816,6 +4816,11 @@ R"( void write_winrt_reference_type_attribute(writer& w, TypeDef const& type) { + if (settings.reference_projection) + { + return; + } + w.write("[WindowsRuntimeReferenceType(typeof(%?))]\n", type.TypeName()); } @@ -4860,6 +4865,11 @@ R"( void write_default_interface_attribute(writer& w, TypeDef const& type) { + if (settings.reference_projection) + { + return; + } + auto default_interface = get_default_interface(type); for_typedef(w, get_type_semantics(default_interface), [&](auto type) @@ -9147,19 +9157,11 @@ return new %(valueReference); { method_signature signature{ get_delegate_invoke(type) }; w.write(R"( -%%%%% delegate % %(%); +%%%% delegate % %(%); )", bind(type), bind(type, false), bind(type), - bind([&](writer& w) - { - if (settings.reference_projection) - { - write_guid_attribute(w, type); - w.write("\n"); - } - }), internal_accessibility(), bind(signature), bind(type, typedef_name_type::Projected, false),