diff --git a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml index b64b411bb..b99c24e07 100644 --- a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml +++ b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage.yml @@ -93,6 +93,18 @@ stages: script: | dir _build\$(BuildPlatform)\$(BuildConfiguration)\AuthoringConsumptionTest\bin _build\$(BuildPlatform)\$(BuildConfiguration)\AuthoringConsumptionTest\bin\AuthoringConsumptionTest.exe --gtest_output=xml:AUTHORINGTEST-$(Build.BuildNumber).xml + exit /b 0 + +# Run WUX Tests + - task: CmdLine@2 + displayName: Run WUX Tests + condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'))) + continueOnError: True + inputs: + workingDirectory: $(Build.SourcesDirectory)\src + script: | + dir _build\$(BuildPlatform)\$(BuildConfiguration)\AuthoringWuxConsumptionTest\bin + _build\$(BuildPlatform)\$(BuildConfiguration)\AuthoringWuxConsumptionTest\bin\AuthoringWuxConsumptionTest.exe --gtest_output=xml:AUTHORINGWUXTEST-$(Build.BuildNumber).xml exit /b 0 # Run Functional Tests diff --git a/nuget/Microsoft.Windows.CsWinRT.Authoring.targets b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets index 98f03ea58..f020d04fc 100644 --- a/nuget/Microsoft.Windows.CsWinRT.Authoring.targets +++ b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets @@ -33,6 +33,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. + diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index 64abdcf40..8fe95eaa2 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -289,6 +289,13 @@ $(CsWinRTInternalProjection) + + + $(CsWinRTUiXamlMode) + true + + + @@ -338,6 +345,16 @@ $(CsWinRTInternalProjection) + + + + true + true + + + false + true + diff --git a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs index 0df8eaf9a..052078819 100644 --- a/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs +++ b/src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs @@ -22,10 +22,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var properties = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => (provider.IsCsWinRTAotOptimizerEnabled(), provider.IsCsWinRTComponent(), provider.IsCsWinRTCcwLookupTableGeneratorEnabled())); + var typeMapper = context.AnalyzerConfigOptionsProvider.Select((options, ct) => options.GlobalOptions.GetUIXamlProjectionsMode()).Select((mode, ct) => new TypeMapper(mode)); + var vtablesToAddFromClassTypes = context.SyntaxProvider.CreateSyntaxProvider( static (n, _) => NeedVtableAttribute(n), - static (n, _) => GetVtableAttributeToAdd(n, false) - ).Where(static vtableAttribute => vtableAttribute != default); + static (n, _) => n) + .Combine(typeMapper) + .Select((t, _) => GetVtableAttributeToAdd(t.Left, t.Right, false)) + .Where(static vtableAttribute => vtableAttribute != default); var vtableAttributesToAdd = vtablesToAddFromClassTypes.Select(static (vtable, _) => vtable.Item1); var adapterTypesToAddOnLookupTable = vtablesToAddFromClassTypes.SelectMany(static (vtable, _) => vtable.Item2); @@ -36,32 +40,39 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // that will already be generated by the component generator. var vtablesFromComponentTypes = context.SyntaxProvider.CreateSyntaxProvider( static (n, _) => IsComponentType(n), - static (n, _) => GetVtableAttributeToAdd(n, true) - ).Where(static vtableAttribute => vtableAttribute != default).Collect().Combine(properties). - // Get component types if only authoring scenario - SelectMany(static ((ImmutableArray<(VtableAttribute vtableAttribute, EquatableArray adapterTypes)> classTypes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) => + static (n, _) => n) + .Combine(typeMapper) + .Select((t, _) => GetVtableAttributeToAdd(t.Left, t.Right, true)) + .Where(static vtableAttribute => vtableAttribute != default).Collect() + .Combine(properties) + // Get component types if only authoring scenario + .SelectMany(static ((ImmutableArray<(VtableAttribute vtableAttribute, EquatableArray adapterTypes)> classTypes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) => value.properties.isCsWinRTComponent ? value.classTypes : ImmutableArray<(VtableAttribute, EquatableArray)>.Empty); var instantiatedTypesToAddOnLookupTable = context.SyntaxProvider.CreateSyntaxProvider( static (n, _) => NeedVtableOnLookupTable(n), - static (n, _) => GetVtableAttributesToAddOnLookupTable(n) - ).Combine(properties) - // Get component types if only authoring scenario - .Select(static (((EquatableArray lookupTable, EquatableArray componentLookupTable) vtableAttributes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) => - value.properties.isCsWinRTComponent ? value.vtableAttributes.componentLookupTable : value.vtableAttributes.lookupTable) - .SelectMany(static (vtable, _) => vtable). - Where(static vtableAttribute => vtableAttribute != null); + static (n, _) => n) + .Combine(typeMapper) + .Select((t, _) => GetVtableAttributesToAddOnLookupTable(t.Left, t.Right)) + .Combine(properties) + // Get component types if only authoring scenario + .Select(static (((EquatableArray lookupTable, EquatableArray componentLookupTable) vtableAttributes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) => + value.properties.isCsWinRTComponent ? value.vtableAttributes.componentLookupTable : value.vtableAttributes.lookupTable) + .SelectMany(static (vtable, _) => vtable) + .Where(static vtableAttribute => vtableAttribute != null); var instantiatedTaskAdapters = context.SyntaxProvider.CreateSyntaxProvider( static (n, _) => IsAsyncOperationMethodCall(n), - static (n, _) => GetVtableAttributesForTaskAdapters(n) - ).Where(static vtableAttribute => vtableAttribute != default). - Combine(properties). - // Get component types if only authoring scenario - Select(static (((VtableAttribute vtableAttribute, VtableAttribute componentVtableAttribute) vtableAttributes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) => - value.properties.isCsWinRTComponent ? value.vtableAttributes.componentVtableAttribute : value.vtableAttributes.vtableAttribute). - Where(static vtableAttribute => vtableAttribute != default). - Collect(); + static (n, _) => n) + .Combine(typeMapper) + .Select((data, ct) => GetVtableAttributesForTaskAdapters(data.Left, data.Right)) + .Where(static vtableAttribute => vtableAttribute != default) + .Combine(properties) + // Get component types if only authoring scenario + .Select(static (((VtableAttribute vtableAttribute, VtableAttribute componentVtableAttribute) vtableAttributes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) => + value.properties.isCsWinRTComponent ? value.vtableAttributes.componentVtableAttribute : value.vtableAttributes.vtableAttribute) + .Where(static vtableAttribute => vtableAttribute != default) + .Collect(); // Merge both adapter types list and instantiated types list var vtablesToAddOnLookupTable = @@ -112,19 +123,22 @@ private static bool IsComponentType(SyntaxNode node) !GeneratorHelper.IsWinRTType(declaration); // Making sure it isn't an RCW we are projecting. } - private static (VtableAttribute, EquatableArray) GetVtableAttributeToAdd(GeneratorSyntaxContext context, bool checkForComponentTypes) + private static (VtableAttribute, EquatableArray) GetVtableAttributeToAdd( + GeneratorSyntaxContext context, + TypeMapper typeMapper, + bool checkForComponentTypes) { var isWinRTTypeFunc = checkForComponentTypes ? GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation) : GeneratorHelper.IsWinRTType; var symbol = context.SemanticModel.GetDeclaredSymbol(context.Node as ClassDeclarationSyntax); - var vtableAttribute = GetVtableAttributeToAdd(symbol, isWinRTTypeFunc, context.SemanticModel.Compilation, false); + var vtableAttribute = GetVtableAttributeToAdd(symbol, isWinRTTypeFunc, typeMapper, context.SemanticModel.Compilation, false); if (vtableAttribute != default) { HashSet vtableAttributesForLookupTable = []; // Add any adapter types which may be needed if certain functions // from some known interfaces are called. - AddVtableAdapterTypeForKnownInterface(symbol, context.SemanticModel.Compilation, isWinRTTypeFunc, vtableAttributesForLookupTable); + AddVtableAdapterTypeForKnownInterface(symbol, context.SemanticModel.Compilation, isWinRTTypeFunc, typeMapper, vtableAttributesForLookupTable); return (vtableAttribute, vtableAttributesForLookupTable.ToImmutableArray()); } @@ -187,7 +201,7 @@ static bool IsAsyncOperationMethodCall(SyntaxNode node) // We do this both assuming this is not an authoring component and is an authoring // component as we don't know that at this stage and the results can vary based on that. // We will choose the right one later when we can combine with properties. - private static (VtableAttribute, VtableAttribute) GetVtableAttributesForTaskAdapters(GeneratorSyntaxContext context) + private static (VtableAttribute, VtableAttribute) GetVtableAttributesForTaskAdapters(GeneratorSyntaxContext context, TypeMapper typeMapper) { if (context.SemanticModel.GetSymbolInfo(context.Node as InvocationExpressionSyntax).Symbol is IMethodSymbol symbol) { @@ -200,8 +214,8 @@ private static (VtableAttribute, VtableAttribute) GetVtableAttributesForTaskAdap if (adpaterType is not null) { var constructedAdapterType = adpaterType.Construct([.. symbol.TypeArguments]); - return (GetVtableAttributeToAdd(constructedAdapterType, GeneratorHelper.IsWinRTType, context.SemanticModel.Compilation, false), - GetVtableAttributeToAdd(constructedAdapterType, GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation), context.SemanticModel.Compilation, false)); + return (GetVtableAttributeToAdd(constructedAdapterType, GeneratorHelper.IsWinRTType, typeMapper, context.SemanticModel.Compilation, false), + GetVtableAttributeToAdd(constructedAdapterType, GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation), typeMapper, context.SemanticModel.Compilation, false)); } } } @@ -306,7 +320,8 @@ private static string GetRuntimeClassName(INamedTypeSymbol type, Func isWinRTType, + Func isWinRTType, + TypeMapper mapper, Compilation compilation, bool isAuthoring, string authoringDefaultInterface = "") @@ -316,7 +331,7 @@ internal static VtableAttribute GetVtableAttributeToAdd( return default; } - if (GeneratorHelper.HasNonInstantiatedWinRTGeneric(symbol)) + if (GeneratorHelper.HasNonInstantiatedWinRTGeneric(symbol, mapper)) { return default; } @@ -333,18 +348,18 @@ internal static VtableAttribute GetVtableAttributeToAdd( // use the specified one. Also for authoring scenarios where we call this for authored WinRT types, // don't generate the runtimeclass name for them as we will rely on the full name for them as we do today. var checkForRuntimeClasName = !GeneratorHelper.HasWinRTRuntimeClassNameAttribute(symbol, compilation) && - (!isAuthoring || (isAuthoring && !isWinRTType(symbol))); + (!isAuthoring || (isAuthoring && !isWinRTType(symbol, mapper))); INamedTypeSymbol interfaceToUseForRuntimeClassName = null; foreach (var iface in symbol.AllInterfaces) { - if (isWinRTType(iface)) + if (isWinRTType(iface, mapper)) { interfacesToAddToVtable.Add(ToFullyQualifiedString(iface)); AddGenericInterfaceInstantiation(iface); CheckForInterfaceToUseForRuntimeClassName(iface); } - if (iface.IsGenericType && TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, null, isWinRTType, out var compatibleIfaces)) + if (iface.IsGenericType && TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, mapper, null, isWinRTType, out var compatibleIfaces)) { foreach (var compatibleIface in compatibleIfaces) { @@ -426,7 +441,7 @@ internal static VtableAttribute GetVtableAttributeToAdd( symbol is IArrayTypeSymbol, isDelegate, symbol.DeclaredAccessibility == Accessibility.Public, - GetRuntimeClassName(interfaceToUseForRuntimeClassName, isWinRTType)); + GetRuntimeClassName(interfaceToUseForRuntimeClassName, type => isWinRTType(type, mapper))); void AddGenericInterfaceInstantiation(INamedTypeSymbol iface) { @@ -445,7 +460,7 @@ void AddGenericInterfaceInstantiation(INamedTypeSymbol iface) genericParameters.Add(new GenericParameter( ToFullyQualifiedString(genericParameter), - GeneratorHelper.GetAbiType(genericParameter), + GeneratorHelper.GetAbiType(genericParameter, mapper), genericParameter.TypeKind)); } @@ -479,7 +494,7 @@ void CheckForInterfaceToUseForRuntimeClassName(INamedTypeSymbol iface) } } - private static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(INamedTypeSymbol type, Stack typeStack, Func isWinRTType, out IList compatibleTypes) + private static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(INamedTypeSymbol type, TypeMapper mapper, Stack typeStack, Func isWinRTType, out IList compatibleTypes) { compatibleTypes = null; @@ -492,7 +507,7 @@ private static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(INamedType } var definition = type.OriginalDefinition; - if (!isWinRTType(definition)) + if (!isWinRTType(definition, mapper)) { return false; } @@ -512,20 +527,20 @@ private static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(INamedType HashSet compatibleTypesForGeneric = new(SymbolEqualityComparer.Default); - if (isWinRTType(type.TypeArguments[0])) + if (isWinRTType(type.TypeArguments[0], mapper)) { compatibleTypesForGeneric.Add(type.TypeArguments[0]); } foreach (var iface in type.TypeArguments[0].AllInterfaces) { - if (isWinRTType(iface)) + if (isWinRTType(iface, mapper)) { compatibleTypesForGeneric.Add(iface); } if (iface.IsGenericType - && TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, typeStack, isWinRTType, out var compatibleIfaces)) + && TryGetCompatibleWindowsRuntimeTypesForVariantType(iface, mapper, typeStack, isWinRTType, out var compatibleIfaces)) { compatibleTypesForGeneric.UnionWith(compatibleIfaces); } @@ -534,7 +549,7 @@ private static bool TryGetCompatibleWindowsRuntimeTypesForVariantType(INamedType var baseType = type.TypeArguments[0].BaseType; while (baseType != null) { - if (isWinRTType(baseType)) + if (isWinRTType(baseType, mapper)) { compatibleTypesForGeneric.Add(baseType); } @@ -837,18 +852,21 @@ node is VariableDeclarationSyntax || node is ReturnStatementSyntax; } - private static (EquatableArray, EquatableArray) GetVtableAttributesToAddOnLookupTable(GeneratorSyntaxContext context) + private static (EquatableArray, EquatableArray) GetVtableAttributesToAddOnLookupTable( + GeneratorSyntaxContext context, + TypeMapper typeMapper) { // Get the lookup table as if we are running in an authoring component scenario and as if we are not // and then use the properties later on when we have access to it to check if we are to choose the right one. // Otherwise we will end up generating lookup tables which don't have vtable entries for authoring types. - return (GetVtableAttributesToAddOnLookupTable(context, GeneratorHelper.IsWinRTType), - GetVtableAttributesToAddOnLookupTable(context, GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation))); + return (GetVtableAttributesToAddOnLookupTable(context, typeMapper, GeneratorHelper.IsWinRTType), + GetVtableAttributesToAddOnLookupTable(context, typeMapper, GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation))); } private static EquatableArray GetVtableAttributesToAddOnLookupTable( GeneratorSyntaxContext context, - Func isWinRTType) + TypeMapper typeMapper, + Func isWinRTType) { HashSet visitedTypes = new(SymbolEqualityComparer.Default); HashSet vtableAttributes = new(); @@ -862,7 +880,7 @@ private static EquatableArray GetVtableAttributesToAddOnLookupT // and end up calling a projection function (i.e. ones generated by XAML compiler) // In theory, another library can also be called which can call a projected function // but not handling those scenarios for now. - (isWinRTType(methodSymbol.ContainingSymbol) || + (isWinRTType(methodSymbol.ContainingSymbol, typeMapper) || SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) { // Get the concrete types directly from the argument rather than @@ -891,13 +909,13 @@ private static EquatableArray GetVtableAttributesToAddOnLookupT { var leftSymbol = context.SemanticModel.GetSymbolInfo(assignment.Left).Symbol; if (leftSymbol is IPropertySymbol propertySymbol && - (isWinRTType(propertySymbol.ContainingSymbol) || + (isWinRTType(propertySymbol.ContainingSymbol, typeMapper) || SymbolEqualityComparer.Default.Equals(propertySymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) { AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), propertySymbol.Type); } else if (leftSymbol is IFieldSymbol fieldSymbol && - (isWinRTType(fieldSymbol.ContainingSymbol) || + (isWinRTType(fieldSymbol.ContainingSymbol, typeMapper) || SymbolEqualityComparer.Default.Equals(fieldSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly))) { AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), fieldSymbol.Type); @@ -965,14 +983,14 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType } visitedTypes.Add(arrayType); - var vtableAtribute = GetVtableAttributeToAdd(arrayType, isWinRTType, context.SemanticModel.Compilation, false); + var vtableAtribute = GetVtableAttributeToAdd(arrayType, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); if (vtableAtribute != default) { vtableAttributes.Add(vtableAtribute); } // Also add the enumerator type to the lookup table as the native caller can call it. - AddEnumeratorAdapterForType(arrayType.ElementType, context.SemanticModel.Compilation, isWinRTType, vtableAttributes); + AddEnumeratorAdapterForType(arrayType.ElementType, typeMapper, context.SemanticModel.Compilation, isWinRTType, vtableAttributes); } } else if (instantiatedType.Type is not null || instantiatedType.ConvertedType is not null) @@ -994,11 +1012,11 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType // information is available. if (instantiatedTypeSymbol.TypeKind == TypeKind.Delegate && instantiatedTypeSymbol.MetadataName.Contains("`") && - isWinRTType(instantiatedTypeSymbol) && + isWinRTType(instantiatedTypeSymbol, typeMapper) && convertedToTypeSymbol.SpecialType == SpecialType.System_Object) { var argumentClassNamedTypeSymbol = instantiatedTypeSymbol as INamedTypeSymbol; - vtableAttributes.Add(GetVtableAttributeToAdd(instantiatedTypeSymbol, isWinRTType, context.SemanticModel.Compilation, false)); + vtableAttributes.Add(GetVtableAttributeToAdd(instantiatedTypeSymbol, isWinRTType, typeMapper, context.SemanticModel.Compilation, false)); } // This handles the case where the source generator wasn't able to run @@ -1010,7 +1028,7 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType // library which happened to not run the AOT optimizer. So as a best effort, // we handle it here. if (instantiatedTypeSymbol.TypeKind == TypeKind.Class && - (instantiatedTypeSymbol.MetadataName.Contains("`") || !isWinRTType(instantiatedTypeSymbol)) && + (instantiatedTypeSymbol.MetadataName.Contains("`") || !isWinRTType(instantiatedTypeSymbol, typeMapper)) && !GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) && // If the type is defined in the same assembly as what the source generator is running on, // we let the WinRTExposedType attribute generator handle it. @@ -1018,13 +1036,13 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType // Make sure the type we are passing is being boxed or cast to another interface. !SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol)) { - var vtableAtribute = GetVtableAttributeToAdd(instantiatedTypeSymbol, isWinRTType, context.SemanticModel.Compilation, false); + var vtableAtribute = GetVtableAttributeToAdd(instantiatedTypeSymbol, isWinRTType, typeMapper, context.SemanticModel.Compilation, false); if (vtableAtribute != default) { vtableAttributes.Add(vtableAtribute); } - AddVtableAdapterTypeForKnownInterface(instantiatedTypeSymbol, context.SemanticModel.Compilation, isWinRTType, vtableAttributes); + AddVtableAdapterTypeForKnownInterface(instantiatedTypeSymbol, context.SemanticModel.Compilation, isWinRTType, typeMapper, vtableAttributes); } } } @@ -1033,13 +1051,13 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType // Any of the IEnumerable interfaces on the vtable can be used to get the enumerator. Given IEnumerable is // a covariant interface, it means that we can end up getting an instance of the enumerable adapter for any one // of those covariant interfaces and thereby need vtable lookup entries for all of them. - private static void AddEnumeratorAdapterForType(ITypeSymbol type, Compilation compilation, Func isWinRTType, HashSet vtableAttributes) + private static void AddEnumeratorAdapterForType(ITypeSymbol type, TypeMapper mapper, Compilation compilation, Func isWinRTType, HashSet vtableAttributes) { var enumerableType = compilation.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1"); if (enumerableType != null) { var constructedEnumerableType = enumerableType.Construct(type); - if (TryGetCompatibleWindowsRuntimeTypesForVariantType(constructedEnumerableType, null, isWinRTType, out var compatibleIfaces)) + if (TryGetCompatibleWindowsRuntimeTypesForVariantType(constructedEnumerableType, mapper, null, isWinRTType, out var compatibleIfaces)) { foreach (var compatibleIface in compatibleIfaces) { @@ -1050,7 +1068,7 @@ private static void AddEnumeratorAdapterForType(ITypeSymbol type, Compilation co if (enumeratorAdapterType != null) { var constructedEnumeratorAdapterType = enumeratorAdapterType.Construct(compatibleIface.TypeArguments[0]); - var vtableAttribute = GetVtableAttributeToAdd(constructedEnumeratorAdapterType, isWinRTType, compilation, false); + var vtableAttribute = GetVtableAttributeToAdd(constructedEnumeratorAdapterType, isWinRTType, mapper, compilation, false); if (vtableAttribute != default) { vtableAttributes.Add(vtableAttribute); @@ -1062,13 +1080,13 @@ private static void AddEnumeratorAdapterForType(ITypeSymbol type, Compilation co } } - internal static void AddVtableAdapterTypeForKnownInterface(ITypeSymbol classType, Compilation compilation, Func isWinRTType, HashSet vtableAttributes) + internal static void AddVtableAdapterTypeForKnownInterface(ITypeSymbol classType, Compilation compilation, Func isWinRTType, TypeMapper mapper, HashSet vtableAttributes) { foreach (var iface in classType.AllInterfaces) { if (iface.MetadataName == "IEnumerable`1") { - AddEnumeratorAdapterForType(iface.TypeArguments[0], compilation, isWinRTType, vtableAttributes); + AddEnumeratorAdapterForType(iface.TypeArguments[0], mapper, compilation, isWinRTType, vtableAttributes); } else if (iface.MetadataName == "IDictionary`2") { @@ -1088,7 +1106,7 @@ void LookupAndAddVtableAttributeForGenericType(string type, ImmutableArray namespaceNames = new(); - - foreach (var @namespace in syntaxReceiver.Namespaces) - { - var model = _context.Compilation.GetSemanticModel(@namespace.SyntaxTree); - var namespaceSymbol = model.GetDeclaredSymbol(@namespace); - - string namespaceString = namespaceSymbol.ToString(); - - bool newNamespaceDeclaration = true; - // Because modules could have a namespace defined in different places (i.e. defines a partial class) - // we can't rely on `Contains` so we manually check that namespace names cannot differ by case only - foreach (var usedNamespaceName in namespaceNames) - { - if (String.Equals(namespaceString, usedNamespaceName, StringComparison.OrdinalIgnoreCase) && - !String.Equals(namespaceString, usedNamespaceName, StringComparison.Ordinal)) - { - newNamespaceDeclaration = false; - Report(WinRTRules.NamespacesDifferByCase, namespaceSymbol.Locations.First(), namespaceString); - } - } - - if (newNamespaceDeclaration) - { - namespaceNames.Add(namespaceString); - } - - if (IsInvalidNamespace(namespaceSymbol, _assemblyName)) - { - Report(WinRTRules.DisjointNamespaceRule, namespaceSymbol.Locations.First(), _assemblyName, namespaceString); - } + + // Used to check for conflicting namespace names + HashSet namespaceNames = new(); + + foreach (var @namespace in syntaxReceiver.Namespaces) + { + var model = _context.Compilation.GetSemanticModel(@namespace.SyntaxTree); + var namespaceSymbol = model.GetDeclaredSymbol(@namespace); + + string namespaceString = namespaceSymbol.ToString(); + + bool newNamespaceDeclaration = true; + // Because modules could have a namespace defined in different places (i.e. defines a partial class) + // we can't rely on `Contains` so we manually check that namespace names cannot differ by case only + foreach (var usedNamespaceName in namespaceNames) + { + if (String.Equals(namespaceString, usedNamespaceName, StringComparison.OrdinalIgnoreCase) && + !String.Equals(namespaceString, usedNamespaceName, StringComparison.Ordinal)) + { + newNamespaceDeclaration = false; + Report(WinRTRules.NamespacesDifferByCase, namespaceSymbol.Locations.First(), namespaceString); + } + } + + if (newNamespaceDeclaration) + { + namespaceNames.Add(namespaceString); + } + + if (IsInvalidNamespace(namespaceSymbol, _assemblyName)) + { + Report(WinRTRules.DisjointNamespaceRule, namespaceSymbol.Locations.First(), _assemblyName, namespaceString); + } } } - private void CheckDeclarations() - { - WinRTSyntaxReceiver syntaxReceiver = (WinRTSyntaxReceiver)_context.SyntaxReceiver; - + private void CheckDeclarations() + { + WinRTSyntaxReceiver syntaxReceiver = (WinRTSyntaxReceiver)_context.SyntaxReceiver; + foreach (var declaration in syntaxReceiver.Declarations) { var model = _context.Compilation.GetSemanticModel(declaration.SyntaxTree); @@ -91,12 +93,12 @@ private void CheckDeclarations() // Check symbol information for whether it is public to properly detect partial types // which can leave out modifier. Also ignore nested types not effectively public - if (symbol.DeclaredAccessibility != Accessibility.Public || - (symbol is ITypeSymbol typeSymbol && !typeSymbol.IsPubliclyAccessible())) - { - continue; - } - + if (symbol.DeclaredAccessibility != Accessibility.Public || + (symbol is ITypeSymbol typeSymbol && !typeSymbol.IsPubliclyAccessible())) + { + continue; + } + if (declaration is ClassDeclarationSyntax @class) { var classId = @class.Identifier; @@ -105,7 +107,7 @@ private void CheckDeclarations() var props = @class.DescendantNodes().OfType().Where(IsPublic); // filter out methods and properties that will be replaced with our custom type mappings - IgnoreCustomTypeMappings(classSymbol, ref publicMethods, ref props); + IgnoreCustomTypeMappings(classSymbol, _typeMapper, ref publicMethods, ref props); if (!classSymbol.IsSealed && !classSymbol.IsStatic) { @@ -116,112 +118,113 @@ private void CheckDeclarations() HasMultipleConstructorsOfSameArity(@class); if (classSymbol.IsGenericType) - { + { Report(WinRTRules.GenericTypeRule, @class.GetLocation(), classId); } // check for things in nonWindowsRuntimeInterfaces - ImplementsInvalidInterface(classSymbol, @class); - - CheckProperties(props, classId); - - // check types -- todo: check for !valid types - CheckMethods(publicMethods, classId); - + ImplementsInvalidInterface(classSymbol, @class); + + CheckProperties(props, classId); + + // check types -- todo: check for !valid types + CheckMethods(publicMethods, classId); + CheckInterfaces(model, @class); } else if (declaration is InterfaceDeclarationSyntax @interface) { var interfaceSym = model.GetDeclaredSymbol(@interface); var methods = @interface.DescendantNodes().OfType(); - var props = @interface.DescendantNodes().OfType().Where(IsPublic); - - // filter out methods and properties that will be replaced with our custom type mappings - IgnoreCustomTypeMappings(interfaceSym, ref methods, ref props); - + var props = @interface.DescendantNodes().OfType().Where(IsPublic); + + // filter out methods and properties that will be replaced with our custom type mappings + IgnoreCustomTypeMappings(interfaceSym, _typeMapper, ref methods, ref props); + if (interfaceSym.IsGenericType) { Report(WinRTRules.GenericTypeRule, @interface.GetLocation(), @interface.Identifier); } - ImplementsInvalidInterface(interfaceSym, @interface); - - CheckProperties(props, @interface.Identifier); - + ImplementsInvalidInterface(interfaceSym, @interface); + + CheckProperties(props, @interface.Identifier); + CheckMethods(methods, @interface.Identifier); - } - else if (declaration is StructDeclarationSyntax @struct) - { - CheckStructFields(@struct); - } + } + else if (declaration is StructDeclarationSyntax @struct) + { + CheckStructFields(@struct); + } } - } - - private void CheckInterfaces(SemanticModel model, ClassDeclarationSyntax @class) - { - var classId = @class.Identifier; + } + + private void CheckInterfaces(SemanticModel model, ClassDeclarationSyntax @class) + { + var classId = @class.Identifier; var classSymbol = model.GetDeclaredSymbol(@class); - - var iWinRTObject = model.Compilation.GetTypeByMetadataName("WinRT.IWinRTObject"); - // validate that the class correctly implements all its interfaces - var methods = classSymbol.GetMembers().OfType().ToList(); - foreach (var iface in classSymbol.AllInterfaces) - { - if (SymbolEqualityComparer.Default.Equals(iface, iWinRTObject)) - { - continue; - } - foreach (var member in iface.GetMembers().OfType()) - { - var impl = classSymbol.FindImplementationForInterfaceMember(member); - if (impl == null) - { - var explicitIfaceImpl = methods.Where(m => IsMethodImpl(m, member)); - if (!explicitIfaceImpl.Any()) - { - Report(WinRTRules.UnimplementedInterface, @class.GetLocation(), classId.Text, iface.ToDisplayString(), member.ToDisplayString()); - } - } - } - } - } - - private bool IsMethodImpl(IMethodSymbol m, IMethodSymbol interfaceMethod) - { - if (m.Name != interfaceMethod.Name) - { - return false; - } - if (!m.Parameters.SequenceEqual(interfaceMethod.Parameters)) - { - return false; - } - - // the return type can be covariant with the interface method's return type (i.e. a sub-type) - if (SymEq(m.ReturnType, interfaceMethod.ReturnType) && !m.ReturnType.AllInterfaces.Contains(interfaceMethod.ReturnType, SymbolEqualityComparer.Default)) - { - return false; - } - return true; - } - - private void IgnoreCustomTypeMappings(INamedTypeSymbol typeSymbol, - ref IEnumerable methods, + + var iWinRTObject = model.Compilation.GetTypeByMetadataName("WinRT.IWinRTObject"); + // validate that the class correctly implements all its interfaces + var methods = classSymbol.GetMembers().OfType().ToList(); + foreach (var iface in classSymbol.AllInterfaces) + { + if (SymbolEqualityComparer.Default.Equals(iface, iWinRTObject)) + { + continue; + } + foreach (var member in iface.GetMembers().OfType()) + { + var impl = classSymbol.FindImplementationForInterfaceMember(member); + if (impl == null) + { + var explicitIfaceImpl = methods.Where(m => IsMethodImpl(m, member)); + if (!explicitIfaceImpl.Any()) + { + Report(WinRTRules.UnimplementedInterface, @class.GetLocation(), classId.Text, iface.ToDisplayString(), member.ToDisplayString()); + } + } + } + } + } + + private bool IsMethodImpl(IMethodSymbol m, IMethodSymbol interfaceMethod) + { + if (m.Name != interfaceMethod.Name) + { + return false; + } + if (!m.Parameters.SequenceEqual(interfaceMethod.Parameters)) + { + return false; + } + + // the return type can be covariant with the interface method's return type (i.e. a sub-type) + if (SymEq(m.ReturnType, interfaceMethod.ReturnType) && !m.ReturnType.AllInterfaces.Contains(interfaceMethod.ReturnType, SymbolEqualityComparer.Default)) + { + return false; + } + return true; + } + + private void IgnoreCustomTypeMappings(INamedTypeSymbol typeSymbol, + TypeMapper typeMapper, + ref IEnumerable methods, ref IEnumerable properties) { - string QualifiedName(INamedTypeSymbol sym) - { - return sym.OriginalDefinition.ContainingNamespace + "." + sym.OriginalDefinition.MetadataName; + string QualifiedName(INamedTypeSymbol sym) + { + return sym.OriginalDefinition.ContainingNamespace + "." + sym.OriginalDefinition.MetadataName; } HashSet classMethods = new(SymbolEqualityComparer.Default); foreach (var @interface in typeSymbol.AllInterfaces. - Where(symbol => GeneratorHelper.MappedCSharpTypes.ContainsKey(QualifiedName(symbol)) || + Where(symbol => typeMapper.HasMappingForType(QualifiedName(symbol)) || WinRTTypeWriter.ImplementedInterfacesWithoutMapping.Contains(QualifiedName(symbol)))) { foreach (var interfaceMember in @interface.GetMembers()) - { + { classMethods.Add(typeSymbol.FindImplementationForInterfaceMember(interfaceMember)); } } @@ -276,9 +279,9 @@ private void HasConflictingParameterName(MethodDeclarationSyntax method) bool IsInvalidParameterName(ParameterSyntax stx) { return stx.Identifier.Value.Equals(GeneratedReturnValueName); } var hasInvalidParams = method.ParameterList.Parameters.Any(IsInvalidParameterName); - if (hasInvalidParams) - { - Report(WinRTRules.ParameterNamedValueRule, method.GetLocation(), method.Identifier); + if (hasInvalidParams) + { + Report(WinRTRules.ParameterNamedValueRule, method.GetLocation(), method.Identifier); } } @@ -307,7 +310,7 @@ private void CheckMethods(IEnumerable methodDeclaration foreach (var arg in methodSym.Parameters) { ReportIfInvalidType(arg.Type, method.GetLocation(), method.Identifier, typeId); - } + } } /* Finishes up the work started by `CheckOverloadAttributes` */ foreach (var thing in overloadsWithoutAttributeMap) @@ -326,9 +329,9 @@ private void CheckProperties(IEnumerable props, Synta var propSym = GetModel(prop.SyntaxTree).GetDeclaredSymbol(prop); var loc = prop.GetLocation(); - if (propSym.GetMethod == null || !propSym.GetMethod.DeclaredAccessibility.Equals(Accessibility.Public)) - { - Report(WinRTRules.PrivateGetterRule, loc, prop.Identifier); + if (propSym.GetMethod == null || !propSym.GetMethod.DeclaredAccessibility.Equals(Accessibility.Public)) + { + Report(WinRTRules.PrivateGetterRule, loc, prop.Identifier); } ReportIfInvalidType(propSym.Type, loc, prop.Identifier, typeId); @@ -345,12 +348,12 @@ private void CheckStructFields(StructDeclarationSyntax @struct) { // delegates not allowed if (@struct.DescendantNodes().OfType().Any()) - { + { Report(WinRTRules.StructHasInvalidFieldRule, @struct.GetLocation(), @struct.Identifier, SimplifySyntaxTypeString(typeof(DelegateDeclarationSyntax).Name)); } // methods not allowed if (@struct.DescendantNodes().OfType().Any()) - { + { Report(WinRTRules.StructHasInvalidFieldRule, @struct.GetLocation(), @struct.Identifier, SimplifySyntaxTypeString(typeof(MethodDeclarationSyntax).Name)); } @@ -358,16 +361,16 @@ private void CheckStructFields(StructDeclarationSyntax @struct) // constructors not allowed if (structSym.Constructors.Length > 1) - { + { Report(WinRTRules.StructHasInvalidFieldRule, @struct.GetLocation(), @struct.Identifier, SimplifySyntaxTypeString(typeof(ConstructorDeclarationSyntax).Name)); } var fields = @struct.DescendantNodes().OfType(); - foreach (var field in fields) + foreach (var field in fields) { // all fields must be public if (!IsPublic(field)) - { + { Report(WinRTRules.StructHasPrivateFieldRule, field.GetLocation(), @struct.Identifier); } @@ -381,14 +384,14 @@ private void CheckStructFields(StructDeclarationSyntax @struct) { IFieldSymbol varFieldSym = (IFieldSymbol)GetModel(variable.SyntaxTree).GetDeclaredSymbol(variable); - if (ValidStructFieldTypes.Contains(varFieldSym.Type.SpecialType) || + if (ValidStructFieldTypes.Contains(varFieldSym.Type.SpecialType) || varFieldSym.Type.TypeKind == TypeKind.Struct || varFieldSym.Type.TypeKind == TypeKind.Enum) { break; } else - { + { Report(WinRTRules.StructHasInvalidFieldRule, variable.GetLocation(), @struct.Identifier, varFieldSym.Name); } } @@ -406,23 +409,23 @@ private void CheckStructFields(StructDeclarationSyntax @struct) /// the authored namespace to checkthe name of the component/winmd /// True iff namespace is disjoint from the assembly name private bool IsInvalidNamespace(INamespaceSymbol @namespace, string assemblyName) - { - if (string.CompareOrdinal(@namespace.ToString(), assemblyName) == 0) - { - return false; - } - + { + if (string.CompareOrdinal(@namespace.ToString(), assemblyName) == 0) + { + return false; + } + var topLevel = @namespace; while (!topLevel.ContainingNamespace.IsGlobalNamespace) - { - if (string.CompareOrdinal(topLevel.ToString(), assemblyName) == 0) - { - return false; + { + if (string.CompareOrdinal(topLevel.ToString(), assemblyName) == 0) + { + return false; } topLevel = topLevel.ContainingNamespace; - } - - return string.CompareOrdinal(topLevel.ToString(), assemblyName) != 0; + } + + return string.CompareOrdinal(topLevel.ToString(), assemblyName) != 0; } ///Array types can only be one dimensional and not System.Array, @@ -430,22 +433,22 @@ private bool IsInvalidNamespace(INamespaceSymbol @namespace, string assemblyName ///The type to checkwhere the type is ///The method or property with this type in its signature /// the type this member (method/prop) lives in - private void ReportIfInvalidType(ITypeSymbol typeSymbol, Location loc, SyntaxToken memberId, SyntaxToken typeId) + private void ReportIfInvalidType(ITypeSymbol typeSymbol, Location loc, SyntaxToken memberId, SyntaxToken typeId) { // If it's of the form int[], it has to be one dimensional - if (typeSymbol.TypeKind == TypeKind.Array) + if (typeSymbol.TypeKind == TypeKind.Array) { IArrayTypeSymbol arrTypeSym = (IArrayTypeSymbol)typeSymbol; // [,,]? - if (arrTypeSym.Rank > 1) - { + if (arrTypeSym.Rank > 1) + { Report(WinRTRules.MultiDimensionalArrayRule, loc, memberId, typeId); return; - } - // [][]? - if (arrTypeSym.ElementType.TypeKind == TypeKind.Array) - { + } + // [][]? + if (arrTypeSym.ElementType.TypeKind == TypeKind.Array) + { Report(WinRTRules.JaggedArrayRule, loc, memberId, typeId); return; } @@ -453,7 +456,7 @@ private void ReportIfInvalidType(ITypeSymbol typeSymbol, Location loc, SyntaxTok // NotValidTypes is an array of types that don't exist in Windows Runtime, so can't be passed between functions in Windows Runtime foreach (var typeName in NotValidTypes) - { + { var notValidTypeSym = GetTypeByMetadataName(typeName); if (SymEq(typeSymbol.OriginalDefinition, notValidTypeSym)) { @@ -467,21 +470,21 @@ private void ReportIfInvalidType(ITypeSymbol typeSymbol, Location loc, SyntaxTok if (typeSymbol.ContainingNamespace != null && !typeSymbol.ContainingNamespace.IsGlobalNamespace) { // ContainingNamespace for Enumerable is just System, but we need System.Linq which is the ContainingSymbol - qualifiedName += typeSymbol.ContainingSymbol + "."; + qualifiedName += typeSymbol.ContainingSymbol + "."; } // instead of TypeName, TypeName`1 qualifiedName += typeSymbol.MetadataName; // GetTypeByMetadataName fails on "System.Linq.Enumerable" & "System.Collections.ObjectModel.ReadOnlyDictionary`2" // Would be fixed by issue #678 on the dotnet/roslyn-sdk repo - foreach (var notValidType in WIPNotValidTypes) + foreach (var notValidType in WIPNotValidTypes) { if (qualifiedName == notValidType) - { + { Report(WinRTRules.UnsupportedTypeRule, loc, memberId, notValidType, SuggestType(notValidType)); return; } } - } + } } } diff --git a/src/Authoring/WinRT.SourceGenerator/Generator.cs b/src/Authoring/WinRT.SourceGenerator/Generator.cs index 5f5dd4314..370e2c437 100644 --- a/src/Authoring/WinRT.SourceGenerator/Generator.cs +++ b/src/Authoring/WinRT.SourceGenerator/Generator.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; @@ -21,11 +21,14 @@ public class ComponentGenerator private Logger Logger { get; } private readonly GeneratorExecutionContext context; private string tempFolder; + private readonly TypeMapper mapper; public ComponentGenerator(GeneratorExecutionContext context) { this.context = context; Logger = new Logger(context); + mapper = new(context.AnalyzerConfigOptions.GlobalOptions.GetUIXamlProjectionsMode()); + // TODO-WuxMux: output a module initializer that validates the MUX/WUX projection mode to ensure that things don't get out of sync. } [SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1035", Justification = "We need to do file IO to invoke the 'cswinrt' tool.")] @@ -158,7 +161,8 @@ public void Generate() assembly, version, metadataBuilder, - Logger); + Logger, + mapper); WinRTSyntaxReceiver syntaxReceiver = (WinRTSyntaxReceiver)context.SyntaxReceiver; Logger.Log("Found " + syntaxReceiver.Declarations.Count + " types"); diff --git a/src/Authoring/WinRT.SourceGenerator/Helper.cs b/src/Authoring/WinRT.SourceGenerator/Helper.cs index 0f72bfbb6..d06a1ff1c 100644 --- a/src/Authoring/WinRT.SourceGenerator/Helper.cs +++ b/src/Authoring/WinRT.SourceGenerator/Helper.cs @@ -231,12 +231,12 @@ private static bool IsFundamentalType(ISymbol type) return type.ToDisplayString() == "System.Guid"; } - public static bool IsWinRTType(ISymbol type) + public static bool IsWinRTType(ISymbol type, TypeMapper mapper) { - return IsWinRTType(type, null); + return IsWinRTType(type, null, mapper); } - public static bool IsWinRTType(ISymbol type, Func isAuthoringWinRTType) + public static bool IsWinRTType(ISymbol type, Func isAuthoringWinRTType, TypeMapper mapper) { bool isProjectedType = type.GetAttributes(). Any(attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeTypeAttribute") == 0) || @@ -244,21 +244,21 @@ public static bool IsWinRTType(ISymbol type, Func isAuthoringWinR if (!isProjectedType & type.ContainingNamespace != null) { - isProjectedType = MappedCSharpTypes.ContainsKey(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); + isProjectedType = mapper.HasMappingForType(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); } // Ensure all generic parameters are WinRT types. if (isProjectedType && type is INamedTypeSymbol namedType && namedType.IsGenericType && !namedType.IsDefinition) { isProjectedType = namedType.TypeArguments.All(t => - IsWinRTType(t, isAuthoringWinRTType) || - (isAuthoringWinRTType != null && isAuthoringWinRTType(t))); + IsWinRTType(t, isAuthoringWinRTType, mapper) || + (isAuthoringWinRTType != null && isAuthoringWinRTType(t, mapper))); } return isProjectedType; } - public static bool IsWinRTType(ISymbol type, ITypeSymbol winrtRuntimeTypeAttribute, bool isComponentProject, IAssemblySymbol currentAssembly) + public static bool IsWinRTType(ISymbol type, ITypeSymbol winrtRuntimeTypeAttribute, TypeMapper mapper, bool isComponentProject, IAssemblySymbol currentAssembly) { if (IsFundamentalType(type)) { @@ -277,7 +277,7 @@ public static bool IsWinRTType(ISymbol type, ITypeSymbol winrtRuntimeTypeAttribu bool isProjectedType = HasAttributeWithType(type, winrtRuntimeTypeAttribute); if (!isProjectedType & type.ContainingNamespace != null) { - isProjectedType = MappedCSharpTypes.ContainsKey(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); + isProjectedType = mapper.HasMappingForType(string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName)); } // Ensure all generic parameters are WinRT types. @@ -286,7 +286,7 @@ type is INamedTypeSymbol namedType && namedType.IsGenericType && !namedType.IsDefinition) { - isProjectedType = namedType.TypeArguments.All(t => IsWinRTType(t, winrtRuntimeTypeAttribute, isComponentProject, currentAssembly)); + isProjectedType = namedType.TypeArguments.All(t => IsWinRTType(t, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly)); } return isProjectedType; @@ -341,14 +341,14 @@ public static bool IsInternalInterfaceFromReferences(INamedTypeSymbol iface, IAs // and is used by a WinRT interface. For instance, List where T is a generic. // If the generic isn't used by any WinRT interface, this returns false as for // instance, we can still generate the vtable attribute for it. - public static bool HasNonInstantiatedWinRTGeneric(ITypeSymbol symbol) + public static bool HasNonInstantiatedWinRTGeneric(ITypeSymbol symbol, TypeMapper mapper) { return symbol is INamedTypeSymbol namedType && (IsArgumentTypeParameter(namedType) || (namedType.TypeArguments.Any(IsArgumentTypeParameter) && namedType.AllInterfaces.Any(iface => iface.TypeArguments.Any(IsArgumentTypeParameter) && // Checks if without the non-instantiated generic, whether it would be a WinRT type. - IsWinRTType(iface.OriginalDefinition, null)))); + IsWinRTType(iface.OriginalDefinition, null, mapper)))); static bool IsArgumentTypeParameter(ITypeSymbol argument) { @@ -411,14 +411,14 @@ public static bool HasAttributeWithType(ISymbol symbol, ITypeSymbol attributeTyp return false; } - public static Func IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(Compilation compilation) + public static Func IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(Compilation compilation) { var winrtTypeAttribute = compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute"); return IsWinRTTypeHelper; - bool IsWinRTTypeHelper(ISymbol type) + bool IsWinRTTypeHelper(ISymbol type, TypeMapper typeMapper) { - return IsWinRTType(type, winrtTypeAttribute, true, compilation.Assembly); + return IsWinRTType(type, winrtTypeAttribute, typeMapper, true, compilation.Assembly); } } @@ -452,7 +452,7 @@ private static string GetAbiTypeForFundamentalType(ISymbol type) return type.ToDisplayString(); } - public static bool IsBlittableValueType(ITypeSymbol type) + public static bool IsBlittableValueType(ITypeSymbol type, TypeMapper typeMapper) { if (!type.IsValueType) { @@ -484,9 +484,9 @@ public static bool IsBlittableValueType(ITypeSymbol type) if (type.ContainingNamespace != null) { string customTypeMapKey = string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName); - if (MappedCSharpTypes.ContainsKey(customTypeMapKey)) + if (typeMapper.HasMappingForType(customTypeMapKey)) { - return MappedCSharpTypes[customTypeMapKey].IsBlittable(); + return typeMapper.GetMappedType(customTypeMapKey).IsBlittable(); } } @@ -501,7 +501,7 @@ public static bool IsBlittableValueType(ITypeSymbol type) { if (typeMember is IFieldSymbol field && !field.IsStatic && - !IsBlittableValueType(field.Type)) + !IsBlittableValueType(field.Type, typeMapper)) { return false; } @@ -510,7 +510,7 @@ public static bool IsBlittableValueType(ITypeSymbol type) return true; } - public static string GetAbiType(ITypeSymbol type) + public static string GetAbiType(ITypeSymbol type, TypeMapper mapper) { if (IsFundamentalType(type)) { @@ -530,13 +530,13 @@ public static string GetAbiType(ITypeSymbol type) if (type.IsValueType) { string customTypeMapKey = string.Join(".", type.ContainingNamespace.ToDisplayString(), type.MetadataName); - if (MappedCSharpTypes.ContainsKey(customTypeMapKey)) + if (mapper.HasMappingForType(customTypeMapKey)) { - string prefix = MappedCSharpTypes[customTypeMapKey].IsBlittable() ? "" : "ABI."; + string prefix = mapper.GetMappedType(customTypeMapKey).IsBlittable() ? "" : "ABI."; return prefix + typeStr; } - if (!IsBlittableValueType(type)) + if (!IsBlittableValueType(type, mapper)) { var winrtHelperAttribute = type.GetAttributes(). Where(attribute => string.CompareOrdinal(attribute.AttributeClass.Name, "WindowsRuntimeHelperTypeAttribute") == 0). diff --git a/src/Authoring/WinRT.SourceGenerator/Properties/launchSettings.json b/src/Authoring/WinRT.SourceGenerator/Properties/launchSettings.json new file mode 100644 index 000000000..ef608ed3b --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "WinRT.SourceGenerator": { + "commandName": "DebugRoslynComponent", + "targetProject": "..\\..\\Projections\\Windows\\Windows.csproj" + } + } +} \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/TypeMapper.cs b/src/Authoring/WinRT.SourceGenerator/TypeMapper.cs new file mode 100644 index 000000000..bfec7684a --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/TypeMapper.cs @@ -0,0 +1,125 @@ +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Text; +using static Generator.GeneratorHelper; + +namespace Generator +{ + internal sealed class TypeMapper + { + private readonly Dictionary typeMapping; + + // Based on whether System.Type is used in an attribute declaration or elsewhere, we need to choose the correct custom mapping + // as attributes don't use the TypeName mapping. + private static (string, string, string, bool, bool) GetSystemTypeCustomMapping(ISymbol containingSymbol) + { + bool isDefinedInAttribute = + containingSymbol != null && + string.CompareOrdinal((containingSymbol as INamedTypeSymbol).BaseType?.ToString(), "System.Attribute") == 0; + return isDefinedInAttribute ? + ("System", "Type", "mscorlib", true, false) : + ("Windows.UI.Xaml.Interop", "TypeName", "Windows.Foundation.UniversalApiContract", false, true); + } + + public TypeMapper(UIXamlProjectionsMode xamlMode) + { + // This should be in sync with the reverse mapping from WinRT.Runtime/Projections.cs and cswinrt/helpers.h. + if (xamlMode == UIXamlProjectionsMode.WindowsUIXaml) + { + typeMapping = new(StringComparer.Ordinal) + { + { "System.DateTimeOffset", new MappedType("Windows.Foundation", "DateTime", "Windows.Foundation.FoundationContract", true, false) }, + { "System.Exception", new MappedType("Windows.Foundation", "HResult", "Windows.Foundation.FoundationContract", true, false) }, + { "System.EventHandler`1", new MappedType("Windows.Foundation", "EventHandler`1", "Windows.Foundation.FoundationContract") }, + { "System.FlagsAttribute", new MappedType("System", "FlagsAttribute", "mscorlib" ) }, + { "System.IDisposable", new MappedType("Windows.Foundation", "IClosable", "Windows.Foundation.FoundationContract") }, + { "System.Nullable`1", new MappedType("Windows.Foundation", "IReference`1", "Windows.Foundation.FoundationContract" ) }, + { "System.Object", new MappedType("System", "Object", "mscorlib" ) }, + { "System.TimeSpan", new MappedType("Windows.Foundation", "TimeSpan", "Windows.Foundation.FoundationContract", true, false) }, + { "System.Uri", new MappedType("Windows.Foundation", "Uri", "Windows.Foundation.FoundationContract") }, + { "System.ComponentModel.INotifyPropertyChanged", new MappedType("Windows.UI.Xaml.Data", "INotifyPropertyChanged", "Windows.UI.Xaml") }, + { "System.ComponentModel.PropertyChangedEventArgs", new MappedType("Windows.UI.Xaml.Data", "PropertyChangedEventArgs", "Windows.UI.Xaml") }, + { "System.ComponentModel.PropertyChangedEventHandler", new MappedType("Windows.UI.Xaml.Data", "PropertyChangedEventHandler", "Windows.UI.Xaml") }, + { "System.Windows.Input.ICommand", new MappedType("Windows.UI.Xaml.Input", "ICommand", "Windows.UI.Xaml") }, + { "System.Collections.IEnumerable", new MappedType("Windows.UI.Xaml.Interop", "IBindableIterable", "Windows.UI.Xaml") }, + { "System.Collections.IList", new MappedType("Windows.UI.Xaml.Interop", "IBindableVector", "Windows.UI.Xaml") }, + { "System.Collections.Specialized.INotifyCollectionChanged", new MappedType("Windows.UI.Xaml.Interop", "INotifyCollectionChanged", "Windows.UI.Xaml") }, + { "System.Collections.Specialized.NotifyCollectionChangedAction", new MappedType("Windows.UI.Xaml.Interop", "NotifyCollectionChangedAction", "Windows.UI.Xaml") }, + { "System.Collections.Specialized.NotifyCollectionChangedEventArgs", new MappedType("Windows.UI.Xaml.Interop", "NotifyCollectionChangedEventArgs", "Windows.UI.Xaml") }, + { "System.Collections.Specialized.NotifyCollectionChangedEventHandler", new MappedType("Windows.UI.Xaml.Interop", "NotifyCollectionChangedEventHandler", "Windows.UI.Xaml") }, + { "WinRT.EventRegistrationToken", new MappedType("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract", true, true) }, + { "System.AttributeTargets", new MappedType("Windows.Foundation.Metadata", "AttributeTargets", "Windows.Foundation.FoundationContract", true, true) }, + { "System.AttributeUsageAttribute", new MappedType("Windows.Foundation.Metadata", "AttributeUsageAttribute", "Windows.Foundation.FoundationContract") }, + { "System.Numerics.Matrix3x2", new MappedType("Windows.Foundation.Numerics", "Matrix3x2", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Matrix4x4", new MappedType("Windows.Foundation.Numerics", "Matrix4x4", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Plane", new MappedType("Windows.Foundation.Numerics", "Plane", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Quaternion", new MappedType("Windows.Foundation.Numerics", "Quaternion", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Vector2", new MappedType("Windows.Foundation.Numerics", "Vector2", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Vector3", new MappedType("Windows.Foundation.Numerics", "Vector3", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Vector4", new MappedType("Windows.Foundation.Numerics", "Vector4", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Type", new MappedType(GetSystemTypeCustomMapping) }, + { "System.Collections.Generic.IEnumerable`1", new MappedType("Windows.Foundation.Collections", "IIterable`1", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IEnumerator`1", new MappedType("Windows.Foundation.Collections", "IIterator`1", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.KeyValuePair`2", new MappedType("Windows.Foundation.Collections", "IKeyValuePair`2", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IReadOnlyDictionary`2", new MappedType("Windows.Foundation.Collections", "IMapView`2", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IDictionary`2", new MappedType("Windows.Foundation.Collections", "IMap`2", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IReadOnlyList`1", new MappedType("Windows.Foundation.Collections", "IVectorView`1", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IList`1", new MappedType("Windows.Foundation.Collections", "IVector`1", "Windows.Foundation.FoundationContract") }, + { "Windows.UI.Color", new MappedType("Windows.UI", "Color", "Windows.Foundation.UniversalApiContract", true, true) }, + }; + } + else + { + typeMapping = new(StringComparer.Ordinal) + { + { "System.DateTimeOffset", new MappedType("Windows.Foundation", "DateTime", "Windows.Foundation.FoundationContract", true, false) }, + { "System.Exception", new MappedType("Windows.Foundation", "HResult", "Windows.Foundation.FoundationContract", true, false) }, + { "System.EventHandler`1", new MappedType("Windows.Foundation", "EventHandler`1", "Windows.Foundation.FoundationContract") }, + { "System.FlagsAttribute", new MappedType("System", "FlagsAttribute", "mscorlib" ) }, + { "System.IDisposable", new MappedType("Windows.Foundation", "IClosable", "Windows.Foundation.FoundationContract") }, + { "System.IServiceProvider", new MappedType("Microsoft.UI.Xaml", "IXamlServiceProvider", "Microsoft.UI") }, + { "System.Nullable`1", new MappedType("Windows.Foundation", "IReference`1", "Windows.Foundation.FoundationContract" ) }, + { "System.Object", new MappedType("System", "Object", "mscorlib" ) }, + { "System.TimeSpan", new MappedType("Windows.Foundation", "TimeSpan", "Windows.Foundation.FoundationContract", true, false) }, + { "System.Uri", new MappedType("Windows.Foundation", "Uri", "Windows.Foundation.FoundationContract") }, + { "System.ComponentModel.DataErrorsChangedEventArgs", new MappedType("Microsoft.UI.Xaml.Data", "DataErrorsChangedEventArgs", "Microsoft.UI") }, + { "System.ComponentModel.INotifyDataErrorInfo", new MappedType("Microsoft.UI.Xaml.Data", "INotifyDataErrorInfo", "Microsoft.UI") }, + { "System.ComponentModel.INotifyPropertyChanged", new MappedType("Microsoft.UI.Xaml.Data", "INotifyPropertyChanged", "Microsoft.UI") }, + { "System.ComponentModel.PropertyChangedEventArgs", new MappedType("Microsoft.UI.Xaml.Data", "PropertyChangedEventArgs", "Microsoft.UI") }, + { "System.ComponentModel.PropertyChangedEventHandler", new MappedType("Microsoft.UI.Xaml.Data", "PropertyChangedEventHandler", "Microsoft.UI") }, + { "System.Windows.Input.ICommand", new MappedType("Microsoft.UI.Xaml.Input", "ICommand", "Microsoft.UI") }, + { "System.Collections.IEnumerable", new MappedType("Microsoft.UI.Xaml.Interop", "IBindableIterable", "Microsoft.UI") }, + { "System.Collections.IList", new MappedType("Microsoft.UI.Xaml.Interop", "IBindableVector", "Microsoft.UI") }, + { "System.Collections.Specialized.INotifyCollectionChanged", new MappedType("Microsoft.UI.Xaml.Interop", "INotifyCollectionChanged", "Microsoft.UI") }, + { "System.Collections.Specialized.NotifyCollectionChangedAction", new MappedType("Microsoft.UI.Xaml.Interop", "NotifyCollectionChangedAction", "Microsoft.UI") }, + { "System.Collections.Specialized.NotifyCollectionChangedEventArgs", new MappedType("Microsoft.UI.Xaml.Interop", "NotifyCollectionChangedEventArgs", "Microsoft.UI") }, + { "System.Collections.Specialized.NotifyCollectionChangedEventHandler", new MappedType("Microsoft.UI.Xaml.Interop", "NotifyCollectionChangedEventHandler", "Microsoft.UI") }, + { "WinRT.EventRegistrationToken", new MappedType("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract", true, true) }, + { "System.AttributeTargets", new MappedType("Windows.Foundation.Metadata", "AttributeTargets", "Windows.Foundation.FoundationContract", true, true) }, + { "System.AttributeUsageAttribute", new MappedType("Windows.Foundation.Metadata", "AttributeUsageAttribute", "Windows.Foundation.FoundationContract") }, + { "System.Numerics.Matrix3x2", new MappedType("Windows.Foundation.Numerics", "Matrix3x2", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Matrix4x4", new MappedType("Windows.Foundation.Numerics", "Matrix4x4", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Plane", new MappedType("Windows.Foundation.Numerics", "Plane", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Quaternion", new MappedType("Windows.Foundation.Numerics", "Quaternion", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Vector2", new MappedType("Windows.Foundation.Numerics", "Vector2", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Vector3", new MappedType("Windows.Foundation.Numerics", "Vector3", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Numerics.Vector4", new MappedType("Windows.Foundation.Numerics", "Vector4", "Windows.Foundation.FoundationContract", true, true) }, + { "System.Type", new MappedType(GetSystemTypeCustomMapping) }, + { "System.Collections.Generic.IEnumerable`1", new MappedType("Windows.Foundation.Collections", "IIterable`1", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IEnumerator`1", new MappedType("Windows.Foundation.Collections", "IIterator`1", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.KeyValuePair`2", new MappedType("Windows.Foundation.Collections", "IKeyValuePair`2", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IReadOnlyDictionary`2", new MappedType("Windows.Foundation.Collections", "IMapView`2", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IDictionary`2", new MappedType("Windows.Foundation.Collections", "IMap`2", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IReadOnlyList`1", new MappedType("Windows.Foundation.Collections", "IVectorView`1", "Windows.Foundation.FoundationContract") }, + { "System.Collections.Generic.IList`1", new MappedType("Windows.Foundation.Collections", "IVector`1", "Windows.Foundation.FoundationContract") }, + { "Windows.UI.Color", new MappedType("Windows.UI", "Color", "Windows.Foundation.UniversalApiContract", true, true) }, + }; + } + } + + public bool HasMappingForType(string typeName) => typeMapping.ContainsKey(typeName); + + public MappedType GetMappedType(string typeName) => typeMapping[typeName]; + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/UIXamlProjectionsMode.cs b/src/Authoring/WinRT.SourceGenerator/UIXamlProjectionsMode.cs new file mode 100644 index 000000000..1bf4cc329 --- /dev/null +++ b/src/Authoring/WinRT.SourceGenerator/UIXamlProjectionsMode.cs @@ -0,0 +1,26 @@ +using Microsoft.CodeAnalysis.Diagnostics; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Generator +{ + internal enum UIXamlProjectionsMode + { + MicrosoftUIXaml, + WindowsUIXaml, + } + + internal static class OptionsHelper + { + public static UIXamlProjectionsMode GetUIXamlProjectionsMode(this AnalyzerConfigOptions options) + { + if (options.TryGetValue("build_property.CsWinRTUIXamlProjections", out var value) && Enum.TryParse(value, out UIXamlProjectionsMode mode)) + { + return mode; + } + + return UIXamlProjectionsMode.MicrosoftUIXaml; + } + } +} diff --git a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj index 66e04a780..357e76314 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj @@ -17,6 +17,7 @@ Copyright (c) Microsoft Corporation. All rights reserved. true $(SolutionDir)WinRT.Runtime\key.snk + true true @@ -31,18 +32,18 @@ - - - True - True - CsWinRTDiagnosticStrings.resx - + + + True + True + CsWinRTDiagnosticStrings.resx + - - - ResXFileCodeGenerator - CsWinRTDiagnosticStrings.Designer.cs - + + + ResXFileCodeGenerator + CsWinRTDiagnosticStrings.Designer.cs + diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs b/src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs index ed2c31bc1..f0f009a15 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs @@ -42,6 +42,8 @@ public override void Initialize(AnalysisContext context) return; } + var typeMapper = new TypeMapper(context.Options.AnalyzerConfigOptionsProvider.GlobalOptions.GetUIXamlProjectionsMode()); + context.RegisterSymbolAction(context => { // Filter to classes that can be passed as objects. @@ -53,13 +55,13 @@ public override void Initialize(AnalysisContext context) // Make sure this is a class that we would generate the WinRTExposedType attribute on // and that it isn't already partial. if (!GeneratorHelper.IsPartial(namedType) && - !GeneratorHelper.IsWinRTType(namedType, winrtTypeAttribute, isComponentProject, context.Compilation.Assembly) && - !GeneratorHelper.HasNonInstantiatedWinRTGeneric(namedType) && + !GeneratorHelper.IsWinRTType(namedType, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly) && + !GeneratorHelper.HasNonInstantiatedWinRTGeneric(namedType, typeMapper) && !GeneratorHelper.HasAttributeWithType(namedType, winrtExposedTypeAttribute)) { foreach (var iface in namedType.AllInterfaces) { - if (GeneratorHelper.IsWinRTType(iface, winrtTypeAttribute, isComponentProject, context.Compilation.Assembly)) + if (GeneratorHelper.IsWinRTType(iface, winrtTypeAttribute, typeMapper, isComponentProject, context.Compilation.Assembly)) { context.ReportDiagnostic(Diagnostic.Create(WinRTRules.ClassNotAotCompatible, namedType.Locations[0], namedType.Name)); return; diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index 5143a1bf5..4154f62a9 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -265,7 +265,7 @@ class WinRTTypeWriter : CSharpSyntaxWalker private readonly Dictionary typeReferenceMapping; private readonly Dictionary assemblyReferenceMapping; private readonly MetadataBuilder metadataBuilder; - + private readonly TypeMapper mapper; private readonly Dictionary typeDefinitionMapping; private TypeDeclaration currentTypeDeclaration; @@ -275,12 +275,14 @@ public WinRTTypeWriter( string assembly, string version, MetadataBuilder metadataBuilder, - Logger logger) + Logger logger, + TypeMapper mapper) { this.assembly = assembly; this.version = version; this.metadataBuilder = metadataBuilder; Logger = logger; + this.mapper = mapper; typeReferenceMapping = new Dictionary(StringComparer.Ordinal); assemblyReferenceMapping = new Dictionary(StringComparer.Ordinal); typeDefinitionMapping = new Dictionary(StringComparer.Ordinal); @@ -435,9 +437,9 @@ private EntityHandle GetTypeReference(ISymbol symbol) var assembly = GetAssemblyForWinRTType(symbol); if (assembly == null) { - if (GeneratorHelper.MappedCSharpTypes.ContainsKey(fullType)) + if (mapper.HasMappingForType(fullType)) { - (@namespace, name, assembly, _, _) = GeneratorHelper.MappedCSharpTypes[fullType].GetMapping(currentTypeDeclaration.Node); + (@namespace, name, assembly, _, _) = mapper.GetMappedType(fullType).GetMapping(currentTypeDeclaration.Node); Logger.Log("custom mapping " + fullType + " to " + QualifiedName(@namespace, name) + " from " + assembly); } else @@ -520,9 +522,9 @@ private void EncodeSymbol(Symbol symbol, SignatureTypeEncoder typeEncoder) else { bool isValueType = symbol.Type.TypeKind == TypeKind.Enum || symbol.Type.TypeKind == TypeKind.Struct; - if (GeneratorHelper.MappedCSharpTypes.ContainsKey(QualifiedName(symbol.Type))) + if (mapper.HasMappingForType(QualifiedName(symbol.Type))) { - (_, _, _, _, isValueType) = GeneratorHelper.MappedCSharpTypes[QualifiedName(symbol.Type)].GetMapping(currentTypeDeclaration.Node); + (_, _, _, _, isValueType) = mapper.GetMappedType(QualifiedName(symbol.Type)).GetMapping(currentTypeDeclaration.Node); } typeEncoder.Type(GetTypeReference(symbol.Type), isValueType); } @@ -804,7 +806,7 @@ private void ProcessCustomMappedInterfaces(INamedTypeSymbol classSymbol) // Mark custom mapped interface members for removal later. // Note we want to also mark members from interfaces without mappings. foreach (var implementedInterface in GetInterfaces(classSymbol, true). - Where(symbol => GeneratorHelper.MappedCSharpTypes.ContainsKey(QualifiedName(symbol)) || + Where(symbol => mapper.HasMappingForType(QualifiedName(symbol)) || ImplementedInterfacesWithoutMapping.Contains(QualifiedName(symbol)))) { bool isPubliclyImplemented = false; @@ -825,7 +827,7 @@ private void ProcessCustomMappedInterfaces(INamedTypeSymbol classSymbol) } foreach (var implementedInterface in GetInterfaces(classSymbol) - .Where(symbol => GeneratorHelper.MappedCSharpTypes.ContainsKey(QualifiedName(symbol)))) + .Where(symbol => mapper.HasMappingForType(QualifiedName(symbol)))) { WriteCustomMappedTypeMembers(implementedInterface, true, isPublicImplementation[implementedInterface]); } @@ -853,9 +855,9 @@ INamedTypeSymbol GetTypeByMetadataName(string metadataName) private string GetMappedQualifiedTypeName(ITypeSymbol symbol) { string qualifiedName = QualifiedName(symbol); - if (GeneratorHelper.MappedCSharpTypes.ContainsKey(qualifiedName)) + if (mapper.HasMappingForType(qualifiedName)) { - var (@namespace, mappedTypeName, _, _, _) = GeneratorHelper.MappedCSharpTypes[qualifiedName].GetMapping(currentTypeDeclaration.Node); + var (@namespace, mappedTypeName, _, _, _) = mapper.GetMappedType(qualifiedName).GetMapping(currentTypeDeclaration.Node); qualifiedName = QualifiedName(@namespace, mappedTypeName); if (symbol is INamedTypeSymbol namedType && namedType.TypeArguments.Length > 0) { @@ -874,7 +876,7 @@ private string GetMappedQualifiedTypeName(ITypeSymbol symbol) private void WriteCustomMappedTypeMembers(INamedTypeSymbol symbol, bool isDefinition, bool isPublic = true) { - var (_, mappedTypeName, _, _, _) = GeneratorHelper.MappedCSharpTypes[QualifiedName(symbol)].GetMapping(currentTypeDeclaration.Node); + var (_, mappedTypeName, _, _, _) = mapper.GetMappedType(QualifiedName(symbol)).GetMapping(currentTypeDeclaration.Node); string qualifiedName = GetMappedQualifiedTypeName(symbol); Logger.Log("writing custom mapped type members for " + mappedTypeName + " public: " + isPublic + " qualified name: " + qualifiedName); @@ -1233,7 +1235,7 @@ void GatherPubliclyAccessibleInterfaces(ITypeSymbol symbol) GatherPubliclyAccessibleInterfaces(symbol); var baseType = symbol.BaseType; - while (baseType != null && !GeneratorHelper.IsWinRTType(baseType)) + while (baseType != null && !GeneratorHelper.IsWinRTType(baseType, mapper)) { GatherPubliclyAccessibleInterfaces(baseType); @@ -2440,9 +2442,9 @@ void AddType(INamedTypeSymbol type, bool treatAsProjectedType = false) { AddProjectedType(type); } - else if (GeneratorHelper.MappedCSharpTypes.ContainsKey(qualifiedName)) + else if (mapper.HasMappingForType(qualifiedName)) { - var (@namespace, name, assembly, isSystemType, _) = GeneratorHelper.MappedCSharpTypes[qualifiedName].GetMapping(); + var (@namespace, name, assembly, isSystemType, _) = mapper.GetMappedType(qualifiedName).GetMapping(); if (isSystemType) { var projectedType = Model.Compilation.GetTypeByMetadataName(QualifiedName(@namespace, name)); @@ -2534,7 +2536,7 @@ public void FinalizeGeneration() Logger.Log("finalizing interface " + implementedInterfaceQualifiedNameWithGenerics); var interfaceTypeDeclaration = typeDefinitionMapping[implementedInterfaceQualifiedNameWithGenerics]; - if (GeneratorHelper.MappedCSharpTypes.ContainsKey(QualifiedName(implementedInterface))) + if (mapper.HasMappingForType(QualifiedName(implementedInterface))) { Logger.Log("adding MethodImpls for custom mapped interface"); foreach (var interfaceMember in interfaceTypeDeclaration.MethodReferences) @@ -2665,11 +2667,11 @@ public void FinalizeGeneration() public void GenerateWinRTExposedClassAttributes(GeneratorExecutionContext context) { - bool IsWinRTType(ISymbol symbol) + bool IsWinRTType(ISymbol symbol, TypeMapper mapper) { if (!SymbolEqualityComparer.Default.Equals(symbol.ContainingAssembly, context.Compilation.Assembly)) { - return GeneratorHelper.IsWinRTType(symbol, IsWinRTType); + return GeneratorHelper.IsWinRTType(symbol, (symbol, mapper) => IsWinRTType(symbol, mapper), mapper); } if (symbol is INamedTypeSymbol namedType) @@ -2703,8 +2705,8 @@ typeDeclaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Class && !symbol.IsStatic) { - vtableAttributesToAdd.Add(WinRTAotSourceGenerator.GetVtableAttributeToAdd(symbol, IsWinRTType, context.Compilation, true, typeDeclaration.DefaultInterface)); - WinRTAotSourceGenerator.AddVtableAdapterTypeForKnownInterface(symbol, context.Compilation, IsWinRTType, vtableAttributesToAddOnLookupTable); + vtableAttributesToAdd.Add(WinRTAotSourceGenerator.GetVtableAttributeToAdd(symbol, IsWinRTType, mapper, context.Compilation, true, typeDeclaration.DefaultInterface)); + WinRTAotSourceGenerator.AddVtableAdapterTypeForKnownInterface(symbol, context.Compilation, IsWinRTType, mapper, vtableAttributesToAddOnLookupTable); } } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 009806607..b7d20d0ae 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -30,6 +30,8 @@ netcoreapp3.1;net6.0;net8.0 netstandard2.0;net6.0;net8.0 netstandard2.0;net6.0;net8.0 + net6.0;net8.0 + net6.0;net8.0 net6.0-windows10.0.19041.0;net7.0-windows10.0.19041.0 net6.0-windows10.0.19041.0 net6.0;net8.0 diff --git a/src/Perf/IIDOptimizer/GuidPatcher.cs b/src/Perf/IIDOptimizer/GuidPatcher.cs index bd200dfd6..e12723150 100644 --- a/src/Perf/IIDOptimizer/GuidPatcher.cs +++ b/src/Perf/IIDOptimizer/GuidPatcher.cs @@ -72,12 +72,14 @@ public GuidPatcher(AssemblyDefinition winRTRuntime, AssemblyDefinition targetAss guidGeneratorType = null; TypeDefinition? typeExtensionsType = null; + TypeDefinition? wuxMuxProjectedInterfaceAttributeType = null; // Use the type definition if we are patching WinRT.Runtime, otherwise lookup the types as references if (string.CompareOrdinal(assembly.Name.Name, "WinRT.Runtime") == 0) { - guidGeneratorType = winRTRuntimeAssembly.MainModule.Types.Where(typeDef => string.CompareOrdinal(typeDef.Name, "GuidGenerator") == 0).First(); - typeExtensionsType = winRTRuntimeAssembly.MainModule.Types.Where(typeDef => string.CompareOrdinal(typeDef.Name, "TypeExtensions") == 0).First(); + guidGeneratorType = winRTRuntimeAssembly.MainModule.Types.Where(typeDef => string.Equals(typeDef.Name, "GuidGenerator", StringComparison.Ordinal)).First(); + typeExtensionsType = winRTRuntimeAssembly.MainModule.Types.Where(typeDef => string.Equals(typeDef.Name, "TypeExtensions", StringComparison.Ordinal)).First(); + wuxMuxProjectedInterfaceAttributeType = winRTRuntimeAssembly.MainModule.Types.Where(typedef => string.Equals(typedef.Name, "WuxMuxProjectedInterfaceAttribute", StringComparison.Ordinal)).First(); } foreach (var asm in assembly.MainModule.AssemblyReferences) @@ -87,6 +89,7 @@ public GuidPatcher(AssemblyDefinition winRTRuntime, AssemblyDefinition targetAss guidGeneratorType = new TypeReference("WinRT", "GuidGenerator", assembly.MainModule, asm).Resolve(); typeExtensionsType = new TypeReference("WinRT", "TypeExtensions", assembly.MainModule, asm).Resolve(); + wuxMuxProjectedInterfaceAttributeType = new TypeReference("WinRT", "WuxMuxProjectedInterfaceAttribute", assembly.MainModule, asm).Resolve(); } else if (string.CompareOrdinal(asm.Name, "System.Runtime.InteropServices") == 0) { @@ -101,7 +104,7 @@ public GuidPatcher(AssemblyDefinition winRTRuntime, AssemblyDefinition targetAss getHelperTypeMethod = typeExtensionsType.Methods.First(m => String.CompareOrdinal(m.Name, "GetHelperType") == 0); } - signatureGenerator = new SignatureGenerator(assembly, guidAttributeType!, winRTRuntimeAssembly); + signatureGenerator = new SignatureGenerator(assembly, guidAttributeType!, wuxMuxProjectedInterfaceAttributeType!, winRTRuntimeAssembly); methodCache = new Dictionary(); } diff --git a/src/Perf/IIDOptimizer/SignatureEmitter.cs b/src/Perf/IIDOptimizer/SignatureEmitter.cs index aa3d6a393..3483105d8 100644 --- a/src/Perf/IIDOptimizer/SignatureEmitter.cs +++ b/src/Perf/IIDOptimizer/SignatureEmitter.cs @@ -35,6 +35,8 @@ sealed record RuntimeGenericSignatureStep(GenericParameter OriginalTypeParameter sealed record RuntimeCustomSignatureStep(MethodReference method) : SignatureStep; + sealed record FallbackSignatureStep(TypeReference type) : SignatureStep; + public SignatureEmitter(TypeReference describedType, MethodDefinition guidDataGetterMethod) { this.describedType = describedType; @@ -76,6 +78,16 @@ public void PushCustomSignature(MethodReference customSignatureMethod) signatureSteps.Add(new RuntimeCustomSignatureStep(customSignatureMethod)); } + public void PushFallback(TypeReference type) + { + if (currentStringBuilder is not null) + { + signatureSteps.Add(new StringStep(currentStringBuilder.ToString())); + currentStringBuilder = null; + } + signatureSteps.Add(new FallbackSignatureStep(type)); + } + public void EmitGuidGetter( TypeDefinition guidDataBlockType, TypeDefinition implementationDetailsType, @@ -289,6 +301,25 @@ private void GenerateGuidFactoryFromComplexSignature(TypeDefinition implementati il.Emit(OpCodes.Stloc, fullSignatureLength); } break; + case FallbackSignatureStep(TypeReference type): + { + // byte[] bytes = Encoding.UTF8.GetBytes(GetSignature(typeof(type))) + il.Emit(OpCodes.Call, utf8EncodingGetter); + il.Emit(OpCodes.Ldtoken, type); + il.Emit(OpCodes.Call, getTypeFromHandleMethod); + il.Emit(OpCodes.Call, getSignatureMethod); + il.Emit(OpCodes.Callvirt, encodingGetBytes); + il.Emit(OpCodes.Dup); + // = new ReadOnlySpan(bytes); + il.Emit(OpCodes.Newobj, readOnlySpanOfByteArrayCtor); + il.Emit(OpCodes.Stloc, signatureParts[i]); + // signatureLength += bytes.Length + il.Emit(OpCodes.Ldlen); + il.Emit(OpCodes.Ldloc, fullSignatureLength); + il.Emit(OpCodes.Add_Ovf); + il.Emit(OpCodes.Stloc, fullSignatureLength); + } + break; default: il.Clear(); throw new InvalidOperationException(); diff --git a/src/Perf/IIDOptimizer/SignatureGenerator.cs b/src/Perf/IIDOptimizer/SignatureGenerator.cs index 7c6fd6282..ce0e7e2ef 100644 --- a/src/Perf/IIDOptimizer/SignatureGenerator.cs +++ b/src/Perf/IIDOptimizer/SignatureGenerator.cs @@ -55,12 +55,14 @@ sealed class SignatureGenerator { private readonly AssemblyDefinition assembly; private readonly TypeDefinition guidAttributeType; + private readonly TypeDefinition wuxMuxProjectedInterfaceAttributeType; private readonly AssemblyDefinition winRTRuntimeAssembly; - public SignatureGenerator(AssemblyDefinition assembly, TypeDefinition guidAttributeType, AssemblyDefinition runtimeAssembly) + public SignatureGenerator(AssemblyDefinition assembly, TypeDefinition guidAttributeType, TypeDefinition wuxMuxProjectedInterfaceAttributeType, AssemblyDefinition runtimeAssembly) { this.assembly = assembly; this.guidAttributeType = guidAttributeType; + this.wuxMuxProjectedInterfaceAttributeType = wuxMuxProjectedInterfaceAttributeType; this.winRTRuntimeAssembly = runtimeAssembly; } @@ -170,6 +172,25 @@ public SignaturePart GetSignatureParts(TypeReference type) return new RuntimeClassSignature(type, GetSignatureParts(iface)); } + // For types projected from WUX or MUX into .NET, we'll need to do a runtime lookup for the IID. + // TODO-WuxMux: We can instead take an option in the IID optimizer to hard-code the lookup for WUX or MUX when specified, which would be more efficient for scenarios where this is possible. + if (helperType?.Resolve().CustomAttributes.Any(attr => attr.AttributeType.Resolve() == wuxMuxProjectedInterfaceAttributeType) == true) + { + var getGuidSignatureMethod = new MethodReference("GetGuidSignature", assembly.MainModule.TypeSystem.String, helperType) + { + HasThis = false + }; + + if (getGuidSignatureMethod.Resolve() is not null) + { + return new CustomSignatureMethod(assembly.MainModule.ImportReference(getGuidSignatureMethod)); + } + else + { + throw new InvalidOperationException($"Unable to resolve GetGuidSignature method for type projected into .NET from WUX/MUX: {type.FullName}."); + } + } + Guid? guidAttributeValue = type.ReadGuidFromAttribute(guidAttributeType, winRTRuntimeAssembly); if (guidAttributeValue == null) { diff --git a/src/Projections/WinAppSDK/WinAppSDK.csproj b/src/Projections/WinAppSDK/WinAppSDK.csproj index b77e179c6..5fd5ae330 100644 --- a/src/Projections/WinAppSDK/WinAppSDK.csproj +++ b/src/Projections/WinAppSDK/WinAppSDK.csproj @@ -35,6 +35,7 @@ -include Windows.UI.Xaml.Media.Animation.ConditionallyIndependentlyAnimatableAttribute -include Windows.UI.Xaml.Media.Animation.IndependentlyAnimatableAttribute -include Windows.UI.Xaml.Media.Animation.ConditionallyIndependentlyAnimatableAttribute + -addition_exclude Windows.UI.Xaml.Media.Animation $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', 'microsoft.windowsappsdk', '$(MicrosoftWinAppSDKVersion)')) diff --git a/src/Projections/WinUI/WinUI.csproj b/src/Projections/WinUI/WinUI.csproj index a3b83d4f6..e5a1e4c35 100644 --- a/src/Projections/WinUI/WinUI.csproj +++ b/src/Projections/WinUI/WinUI.csproj @@ -37,7 +37,8 @@ -include Windows.UI.Xaml.Markup.MarkupExtensionReturnTypeAttribute -include Windows.UI.Xaml.Media.Animation.ConditionallyIndependentlyAnimatableAttribute -include Windows.UI.Xaml.Media.Animation.IndependentlyAnimatableAttribute --include Windows.UI.Xaml.Media.Animation.ConditionallyIndependentlyAnimatableAttribute +-include Windows.UI.Xaml.Media.Animation.ConditionallyIndependentlyAnimatableAttribute +-addition_exclude Windows.UI.Xaml.Media.Animation $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', 'microsoft.winui', '$(MicrosoftWinUIVersion)')) diff --git a/src/Projections/Windows.UI.Xaml/Module.cs b/src/Projections/Windows.UI.Xaml/Module.cs new file mode 100644 index 000000000..636144eed --- /dev/null +++ b/src/Projections/Windows.UI.Xaml/Module.cs @@ -0,0 +1,3 @@ +#if NET +[assembly: global::System.Runtime.Versioning.SupportedOSPlatform("Windows")] +#endif diff --git a/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj b/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj new file mode 100644 index 000000000..f4ca1fa5f --- /dev/null +++ b/src/Projections/Windows.UI.Xaml/Windows.UI.Xaml.csproj @@ -0,0 +1,28 @@ + + + + $(LibBuildTFMsNoNetStandard) + x64;x86 + Microsoft.Windows.UI.Xaml + true + + + + + + + + + + + + + +-exclude Windows +-include Windows.UI.Xaml +-exclude Windows.UI.Xaml.Media.Animation.ConditionallyIndependentlyAnimatableAttribute +-addition_exclude Windows.UI.Xaml.Media.Animation + + + + \ No newline at end of file diff --git a/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.exe.manifest b/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.exe.manifest new file mode 100644 index 000000000..3d69fa84a --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.exe.manifest @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.vcxproj b/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.vcxproj new file mode 100644 index 000000000..64c641b2f --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.vcxproj @@ -0,0 +1,212 @@ + + + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {A04A0416-5E35-4DD0-8226-63D941B28467} + Win32Proj + AuthoringConsumptionTest + Application + v143 + v142 + Unicode + <_WinMDPlatform>$(Platform) + <_WinMDPlatform Condition="'$(Platform)' == 'Win32'">x86 + false + + + + + + + + + + + + + + Create + + + + + + + + true + true + true + true + + + + + {ffa9a78b-f53f-43ee-af87-24a80f4c330a} + TargetFramework=net6.0 + + + {0bb8f82d-874e-45aa-bca3-20ce0562164a} + TargetFramework=net6.0 + + + {7e33bcb7-19c5-4061-981d-ba695322708a} + + + {25244ced-966e-45f2-9711-1f51e951ff89} + TargetFramework=net6.0 + + + {d60cfcad-4a13-4047-91c8-9d7df4753493} + TargetFramework=net6.0 + + + + + ..\AuthoringWuxTest\bin\$(_WinMDPlatform)\$(Configuration)\net6.0\AuthoringWuxTest.winmd + true + + + + + + + + + + + + + + + Use + pch.h + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + true + Console + + + + + Use + pch.h + Disabled + X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + DebugFull + Console + + + + + Use + pch.h + Disabled + X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + DebugFull + Console + + + + + Use + pch.h + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + + + true + Console + true + true + + + + + Use + pch.h + X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + + + true + Console + true + true + + + + + Use + pch.h + X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + + + true + Console + true + true + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.vcxproj.filters b/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.vcxproj.filters new file mode 100644 index 000000000..1332cff35 --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/AuthoringWuxConsumptionTest.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + Source Files + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tests/AuthoringWuxConsumptionTest/Directory.Build.targets b/src/Tests/AuthoringWuxConsumptionTest/Directory.Build.targets new file mode 100644 index 000000000..623267b30 --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/Directory.Build.targets @@ -0,0 +1,16 @@ + + + + $(MSBuildProjectDirectory)/DoNotImport_MsAppxPackageTargets.targets + CopyTestAssets;$(PrepareForRunDependsOn) + + + + + + + + + diff --git a/src/Tests/AuthoringWuxConsumptionTest/DoNotImport_MsAppxPackageTargets.targets b/src/Tests/AuthoringWuxConsumptionTest/DoNotImport_MsAppxPackageTargets.targets new file mode 100644 index 000000000..bcb335b80 --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/DoNotImport_MsAppxPackageTargets.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Tests/AuthoringWuxConsumptionTest/WinRT.Host.runtimeconfig.json b/src/Tests/AuthoringWuxConsumptionTest/WinRT.Host.runtimeconfig.json new file mode 100644 index 000000000..c625b0c81 --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/WinRT.Host.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "rollForward": "LatestMinor", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": "true" + } + } +} \ No newline at end of file diff --git a/src/Tests/AuthoringWuxConsumptionTest/packages.config b/src/Tests/AuthoringWuxConsumptionTest/packages.config new file mode 100644 index 000000000..98b40a750 --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/Tests/AuthoringWuxConsumptionTest/pch.cpp b/src/Tests/AuthoringWuxConsumptionTest/pch.cpp new file mode 100644 index 000000000..bcb5590be --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/src/Tests/AuthoringWuxConsumptionTest/pch.h b/src/Tests/AuthoringWuxConsumptionTest/pch.h new file mode 100644 index 000000000..db3c5d270 --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/pch.h @@ -0,0 +1,26 @@ +#pragma once + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + +#include +#include +#include + +#pragma push_macro("X86") +#pragma push_macro("X64") +#undef X86 +#undef X64 +#include "winrt/Windows.System.h" +#pragma pop_macro("X64") +#pragma pop_macro("X86") + +#include +#include +#include +#include + +#include + +#include "gtest/gtest.h" diff --git a/src/Tests/AuthoringWuxConsumptionTest/test.cpp b/src/Tests/AuthoringWuxConsumptionTest/test.cpp new file mode 100644 index 000000000..b182b935c --- /dev/null +++ b/src/Tests/AuthoringWuxConsumptionTest/test.cpp @@ -0,0 +1,75 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; +using namespace AuthoringWuxTest; + +TEST(AuthoringWuxTest, Collections) +{ + DisposableClass disposed; + disposed.Close(); + MultipleInterfaceMappingClass multipleInterfaces; + Windows::UI::Xaml::Interop::IBindableIterable bindable = multipleInterfaces; + Windows::Foundation::Collections::IVector vector = multipleInterfaces; + Windows::UI::Xaml::Interop::IBindableVector bindableVector = multipleInterfaces; + EXPECT_EQ(vector.Size(), 0); + EXPECT_EQ(bindableVector.Size(), 0); + vector.Append(DisposableClass()); + vector.Append(DisposableClass()); + vector.Append(disposed); + bindableVector.Append(DisposableClass()); + EXPECT_EQ(vector.Size(), 4); + EXPECT_EQ(bindableVector.Size(), 4); + + auto first = vector.First(); + EXPECT_TRUE(first.HasCurrent()); + EXPECT_FALSE(first.Current().IsDisposed()); + auto bindableFirst = bindable.First(); + EXPECT_TRUE(bindableFirst.HasCurrent()); + EXPECT_FALSE(bindableFirst.Current().as().IsDisposed()); + bindableFirst.Current().as().Close(); + EXPECT_TRUE(first.Current().IsDisposed()); + EXPECT_FALSE(vector.GetAt(1).IsDisposed()); + EXPECT_TRUE(vector.GetAt(2).IsDisposed()); + EXPECT_TRUE(bindableVector.First().Current().as().IsDisposed()); + EXPECT_FALSE(bindableVector.GetAt(3).as().IsDisposed()); + EXPECT_TRUE(bindableVector.GetAt(2).as().IsDisposed()); + for (auto obj : vector.GetView()) + { + obj.Close(); + } + + std::array view{}; + EXPECT_EQ(vector.GetMany(1, view), 2); + EXPECT_EQ(view.size(), 2); + for (auto& obj : view) + { + EXPECT_TRUE(obj.IsDisposed()); + } +} + +TEST(AuthoringWuxTest, PropertyChanged) +{ + CustomNotifyPropertyChanged customNotifyPropertyChanged; + Windows::UI::Xaml::Data::INotifyPropertyChanged propChanged = customNotifyPropertyChanged; + winrt::hstring propName = L"Number"; + bool eventTriggered = false; + auto token = propChanged.PropertyChanged(auto_revoke, [&eventTriggered, &propName](IInspectable sender, Windows::UI::Xaml::Data::PropertyChangedEventArgs args) + { + eventTriggered = (args.PropertyName() == propName); + }); + + customNotifyPropertyChanged.RaisePropertyChanged(propName); + + EXPECT_TRUE(eventTriggered); +} + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + winrt::init_apartment(winrt::apartment_type::single_threaded); + auto manager = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread(); + int result = RUN_ALL_TESTS(); + manager.Close(); + return result; +} \ No newline at end of file diff --git a/src/Tests/AuthoringWuxTest/AuthoringWuxTest.csproj b/src/Tests/AuthoringWuxTest/AuthoringWuxTest.csproj new file mode 100644 index 000000000..fbd8d334e --- /dev/null +++ b/src/Tests/AuthoringWuxTest/AuthoringWuxTest.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + x64;x86 + true + true + WindowsUIXaml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tests/AuthoringWuxTest/Directory.Build.props b/src/Tests/AuthoringWuxTest/Directory.Build.props new file mode 100644 index 000000000..4cf186e3d --- /dev/null +++ b/src/Tests/AuthoringWuxTest/Directory.Build.props @@ -0,0 +1,9 @@ + + + + true + + + + + diff --git a/src/Tests/AuthoringWuxTest/Directory.Build.targets b/src/Tests/AuthoringWuxTest/Directory.Build.targets new file mode 100644 index 000000000..8dde12d1b --- /dev/null +++ b/src/Tests/AuthoringWuxTest/Directory.Build.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Tests/AuthoringWuxTest/Module.cs b/src/Tests/AuthoringWuxTest/Module.cs new file mode 100644 index 000000000..636144eed --- /dev/null +++ b/src/Tests/AuthoringWuxTest/Module.cs @@ -0,0 +1,3 @@ +#if NET +[assembly: global::System.Runtime.Versioning.SupportedOSPlatform("Windows")] +#endif diff --git a/src/Tests/AuthoringWuxTest/Program.cs b/src/Tests/AuthoringWuxTest/Program.cs new file mode 100644 index 000000000..004a3cb23 --- /dev/null +++ b/src/Tests/AuthoringWuxTest/Program.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; + +#pragma warning disable CA1416 + +namespace AuthoringWuxTest +{ + public sealed class DisposableClass : IDisposable + { + public bool IsDisposed { get; set; } + + public DisposableClass() + { + IsDisposed = false; + } + + public void Dispose() + { + IsDisposed = true; + } + } + public sealed class CustomNotifyPropertyChanged : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + public void RaisePropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + + public sealed class CustomNotifyCollectionChanged : INotifyCollectionChanged + { + public event NotifyCollectionChangedEventHandler CollectionChanged; + + public void RaiseCollectionChanged(NotifyCollectionChangedEventArgs args) + { + CollectionChanged?.Invoke(this, args); + } + } + + public sealed class CustomEnumerable : IEnumerable + { + private IEnumerable _enumerable; + + public CustomEnumerable(IEnumerable enumerable) + { + _enumerable = enumerable; + } + + public IEnumerator GetEnumerator() + { + return _enumerable.GetEnumerator(); + } + } + + public sealed class MultipleInterfaceMappingClass : IList, IList + { + private List _list = new List(); + + DisposableClass IList.this[int index] { get => _list[index]; set => _list[index] = value; } + object IList.this[int index] { get => _list[index]; set => ((IList)_list) [index] = value; } + + int ICollection.Count => _list.Count; + + int ICollection.Count => _list.Count; + + bool ICollection.IsReadOnly => true; + + bool IList.IsReadOnly => true; + + bool IList.IsFixedSize => false; + + bool ICollection.IsSynchronized => true; + + object ICollection.SyncRoot => ((ICollection) _list).SyncRoot; + + void ICollection.Add(DisposableClass item) + { + _list.Add(item); + } + + int IList.Add(object value) + { + return ((IList) _list).Add(value); + } + + void ICollection.Clear() + { + _list.Clear(); + } + + void IList.Clear() + { + _list.Clear(); + } + + bool ICollection.Contains(DisposableClass item) + { + return _list.Contains(item); + } + + bool IList.Contains(object value) + { + return ((IList) _list).Contains(value); + } + + void ICollection.CopyTo(DisposableClass[] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + void ICollection.CopyTo(Array array, int index) + { + ((ICollection) _list).CopyTo(array, index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _list.GetEnumerator(); + } + + int IList.IndexOf(DisposableClass item) + { + return _list.IndexOf(item); + } + + int IList.IndexOf(object value) + { + return ((IList) _list).IndexOf(value); + } + + void IList.Insert(int index, DisposableClass item) + { + _list.Insert(index, item); + } + + void IList.Insert(int index, object value) + { + ((IList) _list).Insert(index, value); + } + + bool ICollection.Remove(DisposableClass item) + { + return _list.Remove(item); + } + + void IList.Remove(object value) + { + ((IList) _list).Remove(value); + } + + void IList.RemoveAt(int index) + { + _list.RemoveAt(index); + } + + void IList.RemoveAt(int index) + { + _list.RemoveAt(index); + } + } +} diff --git a/src/Tests/AuthoringWuxTest/Properties/launchSettings.json b/src/Tests/AuthoringWuxTest/Properties/launchSettings.json new file mode 100644 index 000000000..c05aeebf5 --- /dev/null +++ b/src/Tests/AuthoringWuxTest/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "AuthoringSample": { + "commandName": "Project", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/src/WinRT.Runtime/Configuration/FeatureSwitches.cs b/src/WinRT.Runtime/Configuration/FeatureSwitches.cs index dbba4db98..41b785de5 100644 --- a/src/WinRT.Runtime/Configuration/FeatureSwitches.cs +++ b/src/WinRT.Runtime/Configuration/FeatureSwitches.cs @@ -4,8 +4,8 @@ using System; using System.Runtime.CompilerServices; -namespace WinRT -{ +namespace WinRT +{ /// /// A container for all shared configuration switches for CsWinRT. /// @@ -19,158 +19,177 @@ namespace WinRT /// For more info, see . /// /// - internal static class FeatureSwitches - { + internal static class FeatureSwitches + { /// /// The configuration property name for . /// - private const string EnablesDynamicObjectsSupportPropertyName = "CSWINRT_ENABLE_DYNAMIC_OBJECTS_SUPPORT"; - + private const string EnableDynamicObjectsSupportPropertyName = "CSWINRT_ENABLE_DYNAMIC_OBJECTS_SUPPORT"; + /// /// The configuration property name for . /// - private const string UseExceptionResourceKeysPropertyName = "CSWINRT_USE_EXCEPTION_RESOURCE_KEYS"; - + private const string UseExceptionResourceKeysPropertyName = "CSWINRT_USE_EXCEPTION_RESOURCE_KEYS"; + /// /// The configuration property name for . /// - private const string EnableDefaultCustomTypeMappingsPropertyName = "CSWINRT_ENABLE_DEFAULT_CUSTOM_TYPE_MAPPINGS"; - + private const string EnableDefaultCustomTypeMappingsPropertyName = "CSWINRT_ENABLE_DEFAULT_CUSTOM_TYPE_MAPPINGS"; + /// /// The configuration property name for . /// - private const string EnableICustomPropertyProviderSupportPropertyName = "CSWINRT_ENABLE_ICUSTOMPROPERTYPROVIDER_SUPPORT"; - + private const string EnableICustomPropertyProviderSupportPropertyName = "CSWINRT_ENABLE_ICUSTOMPROPERTYPROVIDER_SUPPORT"; + /// /// The configuration property name for . /// - private const string EnableIReferenceSupportPropertyName = "CSWINRT_ENABLE_IREFERENCE_SUPPORT"; - + private const string EnableIReferenceSupportPropertyName = "CSWINRT_ENABLE_IREFERENCE_SUPPORT"; + /// /// The configuration property name for . /// - private const string EnableIDynamicInterfaceCastableSupportPropertyName = "CSWINRT_ENABLE_IDYNAMICINTERFACECASTABLE"; - + private const string EnableIDynamicInterfaceCastableSupportPropertyName = "CSWINRT_ENABLE_IDYNAMICINTERFACECASTABLE"; + + /// + /// The configuration property name for . + /// + private const string UseWindowsUIXamlProjectionsPropertyName = "CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS"; + /// /// The backing field for . /// - private static int _enableDynamicObjectsSupportEnabled; - + private static int _enableDynamicObjectsSupport; + /// /// The backing field for . /// - private static int _useExceptionResourceKeys; - + private static int _useExceptionResourceKeys; + /// /// The backing field for . /// - private static int _enableDefaultCustomTypeMappings; - + private static int _enableDefaultCustomTypeMappings; + /// /// The backing field for . /// - private static int _enableICustomPropertyProviderSupport; - + private static int _enableICustomPropertyProviderSupport; + /// /// The backing field for . /// - private static int _enableIReferenceSupport; - + private static int _enableIReferenceSupport; + /// /// The backing field for . /// - private static int _enableIDynamicInterfaceCastableSupport; - + private static int _enableIDynamicInterfaceCastableSupport; + + /// + /// The backing field for . + /// + private static int _useWindowsUIXamlProjections; + /// /// Gets a value indicating whether or not projections support for dynamic objects is enabled (defaults to ). /// - public static bool EnableDynamicObjectsSupport - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetConfigurationValue(EnablesDynamicObjectsSupportPropertyName, ref _enableDynamicObjectsSupportEnabled, true); - } - + public static bool EnableDynamicObjectsSupport + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetConfigurationValue(EnableDynamicObjectsSupportPropertyName, ref _enableDynamicObjectsSupport, true); + } + /// /// Gets a value indicating whether or not exceptions should use resource keys rather than localized messages (defaults to ). /// - public static bool UseExceptionResourceKeys - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetConfigurationValue(UseExceptionResourceKeysPropertyName, ref _useExceptionResourceKeys, false); - } - + public static bool UseExceptionResourceKeys + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetConfigurationValue(UseExceptionResourceKeysPropertyName, ref _useExceptionResourceKeys, false); + } + /// /// Gets a value indicating whether or not should initialize all default type mappings automatically (defaults to ). /// - public static bool EnableDefaultCustomTypeMappings - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetConfigurationValue(EnableDefaultCustomTypeMappingsPropertyName, ref _enableDefaultCustomTypeMappings, true); - } - + public static bool EnableDefaultCustomTypeMappings + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetConfigurationValue(EnableDefaultCustomTypeMappingsPropertyName, ref _enableDefaultCustomTypeMappings, true); + } + /// /// Gets a value indicating whether or not should be enabled (defaults to ). /// - public static bool EnableICustomPropertyProviderSupport - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetConfigurationValue(EnableICustomPropertyProviderSupportPropertyName, ref _enableICustomPropertyProviderSupport, true); - } - + public static bool EnableICustomPropertyProviderSupport + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetConfigurationValue(EnableICustomPropertyProviderSupportPropertyName, ref _enableICustomPropertyProviderSupport, true); + } + /// /// Gets a value indicating whether or not IReference<T>, IReferenceArray<T> and IPropertyValue CCW implementations should be supported (defaults to ). /// - public static bool EnableIReferenceSupport - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetConfigurationValue(EnableIReferenceSupportPropertyName, ref _enableIReferenceSupport, true); - } - + public static bool EnableIReferenceSupport + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetConfigurationValue(EnableIReferenceSupportPropertyName, ref _enableIReferenceSupport, true); + } + /// /// Gets a value indicating whether or not should be supported by RCW types (defaults to ). /// - public static bool EnableIDynamicInterfaceCastableSupport - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetConfigurationValue(EnableIDynamicInterfaceCastableSupportPropertyName, ref _enableIDynamicInterfaceCastableSupport, true); - } - + public static bool EnableIDynamicInterfaceCastableSupport + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetConfigurationValue(EnableIDynamicInterfaceCastableSupportPropertyName, ref _enableIDynamicInterfaceCastableSupport, true); + } + + /// + /// Gets a value indicating whether to project .NET types to their Windows.UI.Xaml equivalents instead of their Microsoft.UI.Xaml equivalents. + /// + public static bool UseWindowsUIXamlProjections + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetConfigurationValue(UseWindowsUIXamlProjectionsPropertyName, ref _useWindowsUIXamlProjections, false); + } + /// /// Gets a configuration value for a specified property. /// /// The property name to retrieve the value for. /// The cached result for the target configuration value. /// The value of the specified configuration setting. - private static bool GetConfigurationValue(string propertyName, ref int cachedResult, bool defaultValue) - { - // The cached switch value has 3 states: - // 0: unknown. - // 1: true - // -1: false - // - // This method doesn't need to worry about concurrent accesses to the cached result, - // as even if the configuration value is retrieved twice, that'll always be the same. - if (cachedResult < 0) - { - return false; - } - - if (cachedResult > 0) - { - return true; - } - - // Get the configuration switch value, or its default. - // All feature switches have a default set in the .targets file. - if (!AppContext.TryGetSwitch(propertyName, out bool isEnabled)) - { - isEnabled = defaultValue; - } - - // Update the cached result - cachedResult = isEnabled ? 1 : -1; - - return isEnabled; - } - } + private static bool GetConfigurationValue(string propertyName, ref int cachedResult, bool defaultValue) + { + // The cached switch value has 3 states: + // 0: unknown. + // 1: true + // -1: false + // + // This method doesn't need to worry about concurrent accesses to the cached result, + // as even if the configuration value is retrieved twice, that'll always be the same. + if (cachedResult < 0) + { + return false; + } + + if (cachedResult > 0) + { + return true; + } + + // Get the configuration switch value, or its default. + // All feature switches have a default set in the .targets file. + if (!AppContext.TryGetSwitch(propertyName, out bool isEnabled)) + { + isEnabled = defaultValue; + } + + // Update the cached result + cachedResult = isEnabled ? 1 : -1; + + return isEnabled; + } + } } \ No newline at end of file diff --git a/src/WinRT.Runtime/Configuration/ILLink.Substitutions.xml b/src/WinRT.Runtime/Configuration/ILLink.Substitutions.xml index 8a04a92b3..c962b9db2 100644 --- a/src/WinRT.Runtime/Configuration/ILLink.Substitutions.xml +++ b/src/WinRT.Runtime/Configuration/ILLink.Substitutions.xml @@ -25,6 +25,10 @@ + + + + diff --git a/src/WinRT.Runtime/GuidGenerator.cs b/src/WinRT.Runtime/GuidGenerator.cs index b02f767ad..b8514f537 100644 --- a/src/WinRT.Runtime/GuidGenerator.cs +++ b/src/WinRT.Runtime/GuidGenerator.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; +using WinRT.Interop; namespace WinRT { @@ -22,7 +23,19 @@ static class GuidGenerator #endif public static Guid GetGUID(Type type) { - return type.GetGuidType().GUID; + type = type.GetGuidType(); + + // Only check the WUX/MUX types if the feature switch is set, to avoid introducing + // performance regressions in the standard case where MUX is targeted (default). + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + if (TryGetWindowsUIXamlIID(type, out Guid iid)) + { + return iid; + } + } + + return type.GUID; } public static Guid GetIID( @@ -32,6 +45,16 @@ public static Guid GetIID( Type type) { type = type.GetGuidType(); + + // Same optional check as above + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + if (TryGetWindowsUIXamlIID(type, out Guid iid)) + { + return iid; + } + } + if (!type.IsGenericType) { return type.GUID; @@ -39,6 +62,48 @@ public static Guid GetIID( return (Guid)type.GetField("PIID").GetValue(null); } + internal static bool TryGetWindowsUIXamlIID(Type type, out Guid iid) + { + if (type == typeof(global::ABI.System.Collections.Specialized.INotifyCollectionChanged)) + { + iid = IID.IID_WUX_INotifyCollectionChanged; + + return true; + } + + if (type == typeof(global::ABI.System.ComponentModel.INotifyPropertyChanged)) + { + iid = IID.IID_WUX_INotifyPropertyChanged; + + return true; + } + + if (type == typeof(global::ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs)) + { + iid = IID.IID_WUX_INotifyCollectionChangedEventArgs; + + return true; + } + + if (type == typeof(global::ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler)) + { + iid = IID.IID_WUX_NotifyCollectionChangedEventHandler; + + return true; + } + + if (type == typeof(global::ABI.System.ComponentModel.PropertyChangedEventHandler)) + { + iid = IID.IID_WUX_PropertyChangedEventHandler; + + return true; + } + + iid = default; + + return false; + } + public static string GetSignature( #if NET // This '[DynamicallyAccessedMembers]' annotation is here just for backwards-compatibility with old projections. Those are diff --git a/src/WinRT.Runtime/Interop/IID.g.cs b/src/WinRT.Runtime/Interop/IID.g.cs index 94d2a90d7..1929b3cd8 100644 --- a/src/WinRT.Runtime/Interop/IID.g.cs +++ b/src/WinRT.Runtime/Interop/IID.g.cs @@ -440,8 +440,108 @@ internal static ref readonly Guid IID_IRestrictedErrorInfo } } - /// The IID for INotifyCollectionChangedEventArgsFactory (5108EBA4-4892-5A20-8374-A96815E0FD27). - internal static ref readonly Guid IID_INotifyCollectionChangedEventArgsFactory + /// The IID for MUX_INotifyPropertyChanged (90B17601-B065-586E-83D9-9ADC3A695284). + internal static ref readonly Guid IID_MUX_INotifyPropertyChanged + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0x01, 0x76, 0xB1, 0x90, + 0x65, 0xB0, + 0x6E, 0x58, + 0x83, + 0xD9, + 0x9A, + 0xDC, + 0x3A, + 0x69, + 0x52, + 0x84 + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for WUX_INotifyPropertyChanged (CF75D69C-F2F4-486B-B302-BB4C09BAEBFA). + internal static ref readonly Guid IID_WUX_INotifyPropertyChanged + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0x9C, 0xD6, 0x75, 0xCF, + 0xF4, 0xF2, + 0x6B, 0x48, + 0xB3, + 0x02, + 0xBB, + 0x4C, + 0x09, + 0xBA, + 0xEB, + 0xFA + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for MUX_INotifyCollectionChanged (530155E1-28A5-5693-87CE-30724D95A06D). + internal static ref readonly Guid IID_MUX_INotifyCollectionChanged + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0xE1, 0x55, 0x01, 0x53, + 0xA5, 0x28, + 0x93, 0x56, + 0x87, + 0xCE, + 0x30, + 0x72, + 0x4D, + 0x95, + 0xA0, + 0x6D + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for WUX_INotifyCollectionChanged (28B167D5-1A31-465B-9B25-D5C3AE686C40). + internal static ref readonly Guid IID_WUX_INotifyCollectionChanged + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0xD5, 0x67, 0xB1, 0x28, + 0x31, 0x1A, + 0x5B, 0x46, + 0x9B, + 0x25, + 0xD5, + 0xC3, + 0xAE, + 0x68, + 0x6C, + 0x40 + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for MUX_INotifyCollectionChangedEventArgsFactory (5108EBA4-4892-5A20-8374-A96815E0FD27). + internal static ref readonly Guid IID_MUX_INotifyCollectionChangedEventArgsFactory { [MethodImpl(MethodImplOptions.AggressiveInlining)] get @@ -465,8 +565,33 @@ internal static ref readonly Guid IID_INotifyCollectionChangedEventArgsFactory } } - /// The IID for INotifyCollectionChangedEventArgs (DA049FF2-D2E0-5FE8-8C7B-F87F26060B6F). - internal static ref readonly Guid IID_INotifyCollectionChangedEventArgs + /// The IID for WUX_INotifyCollectionChangedEventArgsFactory (B30C3E3A-DF8D-44A5-9A38-7AC0D08CE63D). + internal static ref readonly Guid IID_WUX_INotifyCollectionChangedEventArgsFactory + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0x3A, 0x3E, 0x0C, 0xB3, + 0x8D, 0xDF, + 0xA5, 0x44, + 0x9A, + 0x38, + 0x7A, + 0xC0, + 0xD0, + 0x8C, + 0xE6, + 0x3D + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for MUX_INotifyCollectionChangedEventArgs (DA049FF2-D2E0-5FE8-8C7B-F87F26060B6F). + internal static ref readonly Guid IID_MUX_INotifyCollectionChangedEventArgs { [MethodImpl(MethodImplOptions.AggressiveInlining)] get @@ -490,8 +615,83 @@ internal static ref readonly Guid IID_INotifyCollectionChangedEventArgs } } - /// The IID for PropertyChangedEventArgsRuntimeClassFactory (7C0C27A8-0B41-5070-B160-FC9AE960A36C). - internal static ref readonly Guid IID_PropertyChangedEventArgsRuntimeClassFactory + /// The IID for WUX_INotifyCollectionChangedEventArgs (4CF68D33-E3F2-4964-B85E-945B4F7E2F21). + internal static ref readonly Guid IID_WUX_INotifyCollectionChangedEventArgs + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0x33, 0x8D, 0xF6, 0x4C, + 0xF2, 0xE3, + 0x64, 0x49, + 0xB8, + 0x5E, + 0x94, + 0x5B, + 0x4F, + 0x7E, + 0x2F, + 0x21 + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for WUX_MotifyCollectionChangedEventHandler (8B0909DC-2005-5D93-BF8A-725F017BAA8D). + internal static ref readonly Guid IID_MUX_NotifyCollectionChangedEventHandler + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0xDC, 0x09, 0x09, 0x8B, + 0x05, 0x20, + 0x93, 0x5D, + 0xBF, + 0x8A, + 0x72, + 0x5F, + 0x01, + 0x7B, + 0xAA, + 0x8D + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for WUX_NotifyCollectionChangedEventHandler (CA10B37C-F382-4591-8557-5E24965279B0). + internal static ref readonly Guid IID_WUX_NotifyCollectionChangedEventHandler + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0x7C, 0xB3, 0x10, 0xCA, + 0x82, 0xF3, + 0x91, 0x45, + 0x85, + 0x57, + 0x5E, + 0x24, + 0x96, + 0x52, + 0x79, + 0xB0 + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for MUX_PropertyChangedEventArgsRuntimeClassFactory (7C0C27A8-0B41-5070-B160-FC9AE960A36C). + internal static ref readonly Guid IID_MUX_PropertyChangedEventArgsRuntimeClassFactory { [MethodImpl(MethodImplOptions.AggressiveInlining)] get @@ -515,6 +715,81 @@ internal static ref readonly Guid IID_PropertyChangedEventArgsRuntimeClassFactor } } + /// The IID for WUX_PropertyChangedEventArgsRuntimeClassFactory (6DCC9C03-E0C7-4EEE-8EA9-37E3406EEB1C). + internal static ref readonly Guid IID_WUX_PropertyChangedEventArgsRuntimeClassFactory + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0x03, 0x9C, 0xCC, 0x6D, + 0xC7, 0xE0, + 0xEE, 0x4E, + 0x8E, + 0xA9, + 0x37, + 0xE3, + 0x40, + 0x6E, + 0xEB, + 0x1C + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for MUX_PropertyChangedEventHandler (E3DE52F6-1E32-5DA6-BB2D-B5B6096C962D). + internal static ref readonly Guid IID_MUX_PropertyChangedEventHandler + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0xF6, 0x52, 0xDE, 0xE3, + 0x32, 0x1E, + 0xA6, 0x5D, + 0xBB, + 0x2D, + 0xB5, + 0xB6, + 0x09, + 0x6C, + 0x96, + 0x2D + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + + /// The IID for WUX_PropertyChangedEventHandler (50F19C16-0A22-4D8E-A089-1EA9951657D2). + internal static ref readonly Guid IID_WUX_PropertyChangedEventHandler + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ReadOnlySpan data = new byte[] + { + 0x16, 0x9C, 0xF1, 0x50, + 0x22, 0x0A, + 0x8E, 0x4D, + 0xA0, + 0x89, + 0x1E, + 0xA9, + 0x95, + 0x16, + 0x57, + 0xD2 + }; + + return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + } + } + /// The IID for DataErrorsChangedEventArgsRuntimeClassFactory (62D0BD1E-B85F-5FCC-842A-7CB0DDA37FE5). internal static ref readonly Guid IID_DataErrorsChangedEventArgsRuntimeClassFactory { @@ -590,56 +865,6 @@ internal static ref readonly Guid IID_INotifyDataErrorInfo } } - /// The IID for INotifyPropertyChanged (90B17601-B065-586E-83D9-9ADC3A695284). - internal static ref readonly Guid IID_INotifyPropertyChanged - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ReadOnlySpan data = new byte[] - { - 0x01, 0x76, 0xB1, 0x90, - 0x65, 0xB0, - 0x6E, 0x58, - 0x83, - 0xD9, - 0x9A, - 0xDC, - 0x3A, - 0x69, - 0x52, - 0x84 - }; - - return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); - } - } - - /// The IID for INotifyCollectionChanged (530155E1-28A5-5693-87CE-30724D95A06D). - internal static ref readonly Guid IID_INotifyCollectionChanged - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ReadOnlySpan data = new byte[] - { - 0xE1, 0x55, 0x01, 0x53, - 0xA5, 0x28, - 0x93, 0x56, - 0x87, - 0xCE, - 0x30, - 0x72, - 0x4D, - 0x95, - 0xA0, - 0x6D - }; - - return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); - } - } - /// The IID for ICommand (E5AF3542-CA67-4081-995B-709DD13792DF). internal static ref readonly Guid IID_ICommand { @@ -690,56 +915,6 @@ internal static ref readonly Guid IID_IGlobalInterfaceTable } } - /// The IID for PropertyChangedEventHandler (E3DE52F6-1E32-5DA6-BB2D-B5B6096C962D). - internal static ref readonly Guid IID_PropertyChangedEventHandler - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ReadOnlySpan data = new byte[] - { - 0xF6, 0x52, 0xDE, 0xE3, - 0x32, 0x1E, - 0xA6, 0x5D, - 0xBB, - 0x2D, - 0xB5, - 0xB6, - 0x09, - 0x6C, - 0x96, - 0x2D - }; - - return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); - } - } - - /// The IID for NotifyCollectionChangedEventHandler (8B0909DC-2005-5D93-BF8A-725F017BAA8D). - internal static ref readonly Guid IID_NotifyCollectionChangedEventHandler - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ReadOnlySpan data = new byte[] - { - 0xDC, 0x09, 0x09, 0x8B, - 0x05, 0x20, - 0x93, 0x5D, - 0xBF, - 0x8A, - 0x72, - 0x5F, - 0x01, - 0x7B, - 0xAA, - 0x8D - }; - - return ref Unsafe.As(ref MemoryMarshal.GetReference(data)); - } - } - /// The IID for EventHandler (C50898F6-C536-5F47-8583-8B2C2438A13B). internal static ref readonly Guid IID_EventHandler { diff --git a/src/WinRT.Runtime/Interop/IID.tt b/src/WinRT.Runtime/Interop/IID.tt index 47e4fc3a9..17d48ca84 100644 --- a/src/WinRT.Runtime/Interop/IID.tt +++ b/src/WinRT.Runtime/Interop/IID.tt @@ -39,18 +39,25 @@ var entries = new (string Name, string IID, bool IsPublic)[] ("ISupportErrorInfo", "DF0B3D60-548F-101B-8E65-08002B2BD119", false), ("ILanguageExceptionErrorInfo", "04A2DBF3-DF83-116C-0946-0812ABF6E07D", false), ("IRestrictedErrorInfo", "82BA7092-4C88-427D-A7BC-16DD93FEB67E", false), - ("INotifyCollectionChangedEventArgsFactory", "5108EBA4-4892-5A20-8374-A96815E0FD27", false), - ("INotifyCollectionChangedEventArgs", "DA049FF2-D2E0-5FE8-8C7B-F87F26060B6F", false), - ("PropertyChangedEventArgsRuntimeClassFactory", "7C0C27A8-0B41-5070-B160-FC9AE960A36C", false), + ("MUX_INotifyPropertyChanged", "90B17601-B065-586E-83D9-9ADC3A695284", false), + ("WUX_INotifyPropertyChanged", "CF75D69C-F2F4-486B-B302-BB4C09BAEBFA", false), + ("MUX_INotifyCollectionChanged", "530155E1-28A5-5693-87CE-30724D95A06D", false), + ("WUX_INotifyCollectionChanged", "28B167D5-1A31-465B-9B25-D5C3AE686C40", false), + ("MUX_INotifyCollectionChangedEventArgsFactory", "5108EBA4-4892-5A20-8374-A96815E0FD27", false), + ("WUX_INotifyCollectionChangedEventArgsFactory", "B30C3E3A-DF8D-44A5-9A38-7AC0D08CE63D", false), + ("MUX_INotifyCollectionChangedEventArgs", "DA049FF2-D2E0-5FE8-8C7B-F87F26060B6F", false), + ("WUX_INotifyCollectionChangedEventArgs", "4CF68D33-E3F2-4964-B85E-945B4F7E2F21", false), + ("MUX_NotifyCollectionChangedEventHandler", "8B0909DC-2005-5D93-BF8A-725F017BAA8D", false), + ("WUX_NotifyCollectionChangedEventHandler", "CA10B37C-F382-4591-8557-5E24965279B0", false), + ("MUX_PropertyChangedEventArgsRuntimeClassFactory", "7C0C27A8-0B41-5070-B160-FC9AE960A36C", false), + ("WUX_PropertyChangedEventArgsRuntimeClassFactory", "6DCC9C03-E0C7-4EEE-8EA9-37E3406EEB1C", false), + ("MUX_PropertyChangedEventHandler", "E3DE52F6-1E32-5DA6-BB2D-B5B6096C962D", false), + ("WUX_PropertyChangedEventHandler", "50F19C16-0A22-4D8E-A089-1EA9951657D2", false), ("DataErrorsChangedEventArgsRuntimeClassFactory", "62D0BD1E-B85F-5FCC-842A-7CB0DDA37FE5", false), ("UriRuntimeClassFactory", "44A9796F-723E-4FDF-A218-033E75B0C084", false), ("INotifyDataErrorInfo", "0EE6C2CC-273E-567D-BC0A-1DD87EE51EBA", false), - ("INotifyPropertyChanged", "90B17601-B065-586E-83D9-9ADC3A695284", false), - ("INotifyCollectionChanged", "530155E1-28A5-5693-87CE-30724D95A06D", false), ("ICommand", "E5AF3542-CA67-4081-995B-709DD13792DF", false), ("IGlobalInterfaceTable", "00000146-0000-0000-C000-000000000046", false), - ("PropertyChangedEventHandler", "E3DE52F6-1E32-5DA6-BB2D-B5B6096C962D", false), - ("NotifyCollectionChangedEventHandler", "8B0909DC-2005-5D93-BF8A-725F017BAA8D", false), ("EventHandler", "C50898F6-C536-5F47-8583-8B2C2438A13B", false), ("IBindableVectorView", "346DD6E7-976E-4BC3-815D-ECE243BC0F33", false), ("IEnumerable", "036D2C08-DF29-41AF-8AA2-D774BE62BA6F", false), diff --git a/src/WinRT.Runtime/Interop/WuxMuxProjectedTypeAttribute.cs b/src/WinRT.Runtime/Interop/WuxMuxProjectedTypeAttribute.cs new file mode 100644 index 000000000..3f56b6dc7 --- /dev/null +++ b/src/WinRT.Runtime/Interop/WuxMuxProjectedTypeAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace WinRT.Interop +{ + // This attribute is only used by the IIDOptimizer for resolving the signature of a type that has different + // IIDs on WUX/MUX targets. The actual IIDs are hardcoded in WinRT.Runtime, so they are not needed here. + // TODO: remove this entirely when either IIDOptimizer is removed, or when the option to hardcode IIDs is added. + + /// + /// This type signals that the type it is applied to is projected into .NET from either a Windows.UI.Xaml type or a Microsoft.UI.Xaml type. + /// For this type, the GuidAttribute is not used and instead the GetGuidSignature method must be called to get the IID or generic IID signature part of the type. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] + internal sealed class WuxMuxProjectedTypeAttribute : Attribute + { + } +} diff --git a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt index 4040efbcc..1276f8957 100644 --- a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt +++ b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt @@ -232,6 +232,9 @@ CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.Unconditional CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute' exists on 'ABI.WinRT.Interop.IActivationFactory.AsInterface()' in the implementation but not the reference. CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute' exists on 'WinRT.IInspectable.As()' in the implementation but not the reference. CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute' exists on 'WinRT.TypeExtensions.FindHelperType(System.Type)' in the implementation but not the reference. +CannotRemoveAttribute : Attribute 'WinRT.Interop.WuxMuxProjectedTypeAttribute' exists on 'ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler' in the implementation but not the reference. +CannotRemoveAttribute : Attribute 'WinRT.Interop.WuxMuxProjectedTypeAttribute' exists on 'ABI.System.ComponentModel.PropertyChangedEventHandler' in the implementation but not the reference. +CannotRemoveAttribute : Attribute 'WinRT.Interop.WuxMuxProjectedTypeAttribute' exists on 'ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs' in the implementation but not the reference. TypesMustExist : Type 'WinRT.WinRTRuntimeClassNameAttribute' does not exist in the reference but it does exist in the implementation. MembersMustExist : Member 'public void WinRT.ComWrappersSupport.RegisterTypeRuntimeClassNameLookup(System.Func)' does not exist in the reference but it does exist in the implementation. CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute' exists on 'WinRT.Projections.FindCustomHelperTypeMapping(System.Type, System.Boolean)' in the implementation but not the reference. @@ -264,4 +267,4 @@ MembersMustExist : Member 'public void WinRT.ComWrappersHelper.Init(System.Boole MembersMustExist : Member 'public System.Guid ABI.System.EventHandler.IID.get()' does not exist in the reference but it does exist in the implementation. MembersMustExist : Member 'public System.Guid ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler.IID.get()' does not exist in the reference but it does exist in the implementation. MembersMustExist : Member 'public System.Guid ABI.System.ComponentModel.PropertyChangedEventHandler.IID.get()' does not exist in the reference but it does exist in the implementation. -Total Issues: 265 +Total Issues: 268 diff --git a/src/WinRT.Runtime/Projections.CustomTypeMappings.g.cs b/src/WinRT.Runtime/Projections.CustomTypeMappings.g.cs index a45d5e0e8..86e3658ec 100644 --- a/src/WinRT.Runtime/Projections.CustomTypeMappings.g.cs +++ b/src/WinRT.Runtime/Projections.CustomTypeMappings.g.cs @@ -506,6 +506,11 @@ public static void RegisterDataErrorsChangedEventArgsMapping() return; } + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + throw new NotSupportedException("The 'DataErrorsChangedEventArgs' type is only supported for WinUI, and not when using System XAML projections (make sure the 'CsWinRTUseWindowsUIXamlProjections' property is not set to 'true')."); + } + if (Interlocked.CompareExchange(ref _DataErrorsChangedEventArgs, 1, 0) == 1) { return; @@ -531,11 +536,22 @@ public static void RegisterPropertyChangedEventArgsMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(PropertyChangedEventArgs), - typeof(ABI.System.ComponentModel.PropertyChangedEventArgs), - "Microsoft.UI.Xaml.Data.PropertyChangedEventArgs", - isRuntimeClass: true); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(PropertyChangedEventArgs), + typeof(ABI.System.ComponentModel.PropertyChangedEventArgs), + "Windows.UI.Xaml.Data.PropertyChangedEventArgs", + isRuntimeClass: true); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(PropertyChangedEventArgs), + typeof(ABI.System.ComponentModel.PropertyChangedEventArgs), + "Microsoft.UI.Xaml.Data.PropertyChangedEventArgs", + isRuntimeClass: true); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.Data.PropertyChangedEventHandler" WinRT type. @@ -551,11 +567,22 @@ public static void RegisterPropertyChangedEventHandlerMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(PropertyChangedEventHandler), - typeof(ABI.System.ComponentModel.PropertyChangedEventHandler), - "Microsoft.UI.Xaml.Data.PropertyChangedEventHandler", - isRuntimeClass: false); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(PropertyChangedEventHandler), + typeof(ABI.System.ComponentModel.PropertyChangedEventHandler), + "Windows.UI.Xaml.Data.PropertyChangedEventHandler", + isRuntimeClass: false); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(PropertyChangedEventHandler), + typeof(ABI.System.ComponentModel.PropertyChangedEventHandler), + "Microsoft.UI.Xaml.Data.PropertyChangedEventHandler", + isRuntimeClass: false); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.Data.INotifyDataErrorInfo" WinRT type. @@ -566,6 +593,11 @@ public static void RegisterINotifyDataErrorInfoMapping() return; } + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + throw new NotSupportedException("The 'INotifyDataErrorInfo' type is only supported for WinUI, and not when using System XAML projections (make sure the 'CsWinRTUseWindowsUIXamlProjections' property is not set to 'true')."); + } + if (Interlocked.CompareExchange(ref _INotifyDataErrorInfo, 1, 0) == 1) { return; @@ -591,11 +623,22 @@ public static void RegisterINotifyPropertyChangedMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(INotifyPropertyChanged), - typeof(ABI.System.ComponentModel.INotifyPropertyChanged), - "Microsoft.UI.Xaml.Data.INotifyPropertyChanged", - isRuntimeClass: false); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(INotifyPropertyChanged), + typeof(ABI.System.ComponentModel.INotifyPropertyChanged), + "Windows.UI.Xaml.Data.INotifyPropertyChanged", + isRuntimeClass: false); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(INotifyPropertyChanged), + typeof(ABI.System.ComponentModel.INotifyPropertyChanged), + "Microsoft.UI.Xaml.Data.INotifyPropertyChanged", + isRuntimeClass: false); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.Interop.ICommand" WinRT type. @@ -611,11 +654,22 @@ public static void RegisterICommandMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(ICommand), - typeof(ABI.System.Windows.Input.ICommand), - "Microsoft.UI.Xaml.Interop.ICommand", - isRuntimeClass: false); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(ICommand), + typeof(ABI.System.Windows.Input.ICommand), + "Windows.UI.Xaml.Interop.ICommand", + isRuntimeClass: false); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(ICommand), + typeof(ABI.System.Windows.Input.ICommand), + "Microsoft.UI.Xaml.Interop.ICommand", + isRuntimeClass: false); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.IXamlServiceProvider" WinRT type. @@ -626,6 +680,11 @@ public static void RegisterIServiceProviderMapping() return; } + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + throw new NotSupportedException("The 'IServiceProvider' type is only supported for WinUI, and not when using System XAML projections (make sure the 'CsWinRTUseWindowsUIXamlProjections' property is not set to 'true')."); + } + if (Interlocked.CompareExchange(ref _IServiceProvider, 1, 0) == 1) { return; @@ -831,11 +890,22 @@ public static void RegisterIEnumerableMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(IEnumerable), - typeof(ABI.System.Collections.IEnumerable), - "Microsoft.UI.Xaml.Interop.IBindableIterable", - isRuntimeClass: false); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(IEnumerable), + typeof(ABI.System.Collections.IEnumerable), + "Windows.UI.Xaml.Interop.IBindableIterable", + isRuntimeClass: false); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(IEnumerable), + typeof(ABI.System.Collections.IEnumerable), + "Microsoft.UI.Xaml.Interop.IBindableIterable", + isRuntimeClass: false); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.Interop.IBindableVector" WinRT type. @@ -851,11 +921,22 @@ public static void RegisterIListMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(IList), - typeof(ABI.System.Collections.IList), - "Microsoft.UI.Xaml.Interop.IBindableVector", - isRuntimeClass: false); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(IList), + typeof(ABI.System.Collections.IList), + "Windows.UI.Xaml.Interop.IBindableVector", + isRuntimeClass: false); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(IList), + typeof(ABI.System.Collections.IList), + "Microsoft.UI.Xaml.Interop.IBindableVector", + isRuntimeClass: false); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.Interop.INotifyCollectionChanged" WinRT type. @@ -871,11 +952,22 @@ public static void RegisterINotifyCollectionChangedMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(INotifyCollectionChanged), - typeof(ABI.System.Collections.Specialized.INotifyCollectionChanged), - "Microsoft.UI.Xaml.Interop.INotifyCollectionChanged", - isRuntimeClass: false); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(INotifyCollectionChanged), + typeof(ABI.System.Collections.Specialized.INotifyCollectionChanged), + "Windows.UI.Xaml.Interop.INotifyCollectionChanged", + isRuntimeClass: false); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(INotifyCollectionChanged), + typeof(ABI.System.Collections.Specialized.INotifyCollectionChanged), + "Microsoft.UI.Xaml.Interop.INotifyCollectionChanged", + isRuntimeClass: false); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction" WinRT type. @@ -891,11 +983,22 @@ public static void RegisterNotifyCollectionChangedActionMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(NotifyCollectionChangedAction), - typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedAction), - "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction", - isRuntimeClass: false); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(NotifyCollectionChangedAction), + typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedAction), + "Windows.UI.Xaml.Interop.NotifyCollectionChangedAction", + isRuntimeClass: false); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(NotifyCollectionChangedAction), + typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedAction), + "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction", + isRuntimeClass: false); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs" WinRT type. @@ -911,11 +1014,22 @@ public static void RegisterNotifyCollectionChangedEventArgsMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(NotifyCollectionChangedEventArgs), - typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs), - "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", - isRuntimeClass: true); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(NotifyCollectionChangedEventArgs), + typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs), + "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", + isRuntimeClass: true); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(NotifyCollectionChangedEventArgs), + typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs), + "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", + isRuntimeClass: true); + } } /// Registers the custom ABI type mapping for the "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventHandler" WinRT type. @@ -931,11 +1045,22 @@ public static void RegisterNotifyCollectionChangedEventHandlerMapping() return; } - RegisterCustomAbiTypeMapping( - typeof(NotifyCollectionChangedEventHandler), - typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler), - "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventHandler", - isRuntimeClass: false); + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(NotifyCollectionChangedEventHandler), + typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler), + "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler", + isRuntimeClass: false); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(NotifyCollectionChangedEventHandler), + typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler), + "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventHandler", + isRuntimeClass: false); + } } /// Registers the custom ABI type mapping for the "Windows.Foundation.Numerics.Matrix3x2" WinRT type. diff --git a/src/WinRT.Runtime/Projections.CustomTypeMappings.tt b/src/WinRT.Runtime/Projections.CustomTypeMappings.tt index 3d244beb8..8457dc046 100644 --- a/src/WinRT.Runtime/Projections.CustomTypeMappings.tt +++ b/src/WinRT.Runtime/Projections.CustomTypeMappings.tt @@ -50,6 +50,21 @@ void WriteGuardStatements(string name) { return; } +<# + + if (name == "DataErrorsChangedEventArgs" || + name == "INotifyDataErrorInfo" || + name == "IServiceProvider") + { + WriteLine(""); +#> + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + throw new NotSupportedException("The '<#=name#>' type is only supported for WinUI, and not when using System XAML projections (make sure the 'CsWinRTUseWindowsUIXamlProjections' property is not set to 'true')."); + } +<# + } +#> if (Interlocked.CompareExchange(ref _<#=Regex.Replace(name, "[?<>,]", "_")#>, 1, 0) == 1) { @@ -110,7 +125,7 @@ var registerCustomAbiTypeMappings = new (string Public, string Abi, string Name, ("Quaternion", "ABI.System.Numerics.Quaternion", "Windows.Foundation.Numerics.Quaternion", null, false), ("Vector2", "ABI.System.Numerics.Vector2", "Windows.Foundation.Numerics.Vector2", null, false), ("Vector3", "ABI.System.Numerics.Vector3", "Windows.Foundation.Numerics.Vector3", null, false), - ("Vector4", "ABI.System.Numerics.Vector4", "Windows.Foundation.Numerics.Vector4", null, false), + ("Vector4", "ABI.System.Numerics.Vector4", "Windows.Foundation.Numerics.Vector4", null, false) }; // Types for 'RegisterCustomTypeToHelperTypeMapping' @@ -126,6 +141,21 @@ var registerCustomTypeToHelperTypeMapping = new (string Public, string Helper)[] ("ICollection", "ABI.System.Collections.ICollection") }; +// Types that have different projections for System XAML +var systemXamlProjectionTypeMapping = new(string Public, string Name)[] +{ + ("PropertyChangedEventArgs", "Windows.UI.Xaml.Data.PropertyChangedEventArgs"), + ("PropertyChangedEventHandler", "Windows.UI.Xaml.Data.PropertyChangedEventHandler"), + ("INotifyPropertyChanged", "Windows.UI.Xaml.Data.INotifyPropertyChanged"), + ("ICommand", "Windows.UI.Xaml.Interop.ICommand"), + ("IEnumerable", "Windows.UI.Xaml.Interop.IBindableIterable"), + ("IList", "Windows.UI.Xaml.Interop.IBindableVector"), + ("INotifyCollectionChanged", "Windows.UI.Xaml.Interop.INotifyCollectionChanged"), + ("NotifyCollectionChangedAction", "Windows.UI.Xaml.Interop.NotifyCollectionChangedAction"), + ("NotifyCollectionChangedEventArgs", "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs"), + ("NotifyCollectionChangedEventHandler", "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler") +}; + // Declare all fields foreach (string fieldName in registerCustomAbiTypeMappings @@ -145,40 +175,50 @@ foreach (var type in registerCustomAbiTypeMappings) { WriteLine(""); - if (type.Name != null) - { #> /// Registers the custom ABI type mapping for the "<#=type.Name#>" WinRT type. public static void <#=GetMethodName(type.Public, type.Hint)#>() { <# WriteGuardStatements(type.Public); -#> + WriteLine(""); + + int indexOfSystemXamlTypeMapping = Array.FindIndex(systemXamlProjectionTypeMapping, t => t.Public == type.Public); + if (indexOfSystemXamlTypeMapping != -1) + { +#> + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMapping( + typeof(<#=type.Public#>), + typeof(<#=type.Abi#>), + "<#=systemXamlProjectionTypeMapping[indexOfSystemXamlTypeMapping].Name#>", + isRuntimeClass: <#=type.IsRuntimeClass.ToString().ToLowerInvariant()#>); + } + else + { + RegisterCustomAbiTypeMapping( + typeof(<#=type.Public#>), + typeof(<#=type.Abi#>), + "<#=type.Name#>", + isRuntimeClass: <#=type.IsRuntimeClass.ToString().ToLowerInvariant()#>); + } +<# + } + else + { +#> RegisterCustomAbiTypeMapping( typeof(<#=type.Public#>), typeof(<#=type.Abi#>), "<#=type.Name#>", isRuntimeClass: <#=type.IsRuntimeClass.ToString().ToLowerInvariant()#>); - } <# - } - else - { -#> - /// Registers the custom ABI type mapping for the type. - public static void <#=GetMethodName(type.Public, type.Hint)#>() - { -<# - WriteGuardStatements(type.Public); + } #> - - RegisterCustomAbiTypeMapping( - typeof(<#=type.Public#>), - typeof(<#=type.Abi#>)); } <# - } } // 'RegisterCustomTypeToHelperTypeMapping' methods diff --git a/src/WinRT.Runtime/Projections.cs b/src/WinRT.Runtime/Projections.cs index 734bc8f0d..21e992799 100644 --- a/src/WinRT.Runtime/Projections.cs +++ b/src/WinRT.Runtime/Projections.cs @@ -39,6 +39,7 @@ static Projections() { // We always register mappings for 'bool' and 'char' as they're primitive types. // They're also very cheap anyway and commonly used, so this keeps things simpler. + // This should be in sync with cswinrt/helpers.h and the reverse mapping from WinRT.SourceGenerator/TypeMapper.cs. RegisterCustomAbiTypeMappingNoLock(typeof(bool), typeof(ABI.System.Boolean), "Boolean"); RegisterCustomAbiTypeMappingNoLock(typeof(char), typeof(ABI.System.Char), "Char"); @@ -56,6 +57,15 @@ static Projections() } #endif +#if !NET + // Sanity check: always throw downlevel if System XAML projections are used, as this scenario is not supported. + // This also allows other code in WinRT.Runtime to simplify downlevel paths by just assuming this configuration. + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + throw new NotSupportedException("Using System XAML projections is only supported on modern .NET (make sure the 'CsWinRTUseWindowsUIXamlProjections' property is not set to 'true')."); + } +#endif + // This should be in sync with cswinrt/helpers.h and the reverse mapping from WinRT.SourceGenerator/WinRTTypeWriter.cs. RegisterCustomAbiTypeMappingNoLock(typeof(EventRegistrationToken), typeof(ABI.WinRT.EventRegistrationToken), "Windows.Foundation.EventRegistrationToken"); @@ -65,13 +75,37 @@ static Projections() RegisterCustomAbiTypeMappingNoLock(typeof(Exception), typeof(ABI.System.Exception), "Windows.Foundation.HResult"); RegisterCustomAbiTypeMappingNoLock(typeof(TimeSpan), typeof(ABI.System.TimeSpan), "Windows.Foundation.TimeSpan"); RegisterCustomAbiTypeMappingNoLock(typeof(Uri), typeof(ABI.System.Uri), "Windows.Foundation.Uri", isRuntimeClass: true); - RegisterCustomAbiTypeMappingNoLock(typeof(DataErrorsChangedEventArgs), typeof(ABI.System.ComponentModel.DataErrorsChangedEventArgs), "Microsoft.UI.Xaml.Data.DataErrorsChangedEventArgs", isRuntimeClass: true); - RegisterCustomAbiTypeMappingNoLock(typeof(PropertyChangedEventArgs), typeof(ABI.System.ComponentModel.PropertyChangedEventArgs), "Microsoft.UI.Xaml.Data.PropertyChangedEventArgs", isRuntimeClass: true); - RegisterCustomAbiTypeMappingNoLock(typeof(PropertyChangedEventHandler), typeof(ABI.System.ComponentModel.PropertyChangedEventHandler), "Microsoft.UI.Xaml.Data.PropertyChangedEventHandler"); - RegisterCustomAbiTypeMappingNoLock(typeof(INotifyDataErrorInfo), typeof(ABI.System.ComponentModel.INotifyDataErrorInfo), "Microsoft.UI.Xaml.Data.INotifyDataErrorInfo"); - RegisterCustomAbiTypeMappingNoLock(typeof(INotifyPropertyChanged), typeof(ABI.System.ComponentModel.INotifyPropertyChanged), "Microsoft.UI.Xaml.Data.INotifyPropertyChanged"); - RegisterCustomAbiTypeMappingNoLock(typeof(ICommand), typeof(ABI.System.Windows.Input.ICommand), "Microsoft.UI.Xaml.Input.ICommand"); - RegisterCustomAbiTypeMappingNoLock(typeof(IServiceProvider), typeof(ABI.System.IServiceProvider), "Microsoft.UI.Xaml.IXamlServiceProvider"); + + if (!FeatureSwitches.UseWindowsUIXamlProjections) + { + RegisterCustomAbiTypeMappingNoLock(typeof(DataErrorsChangedEventArgs), typeof(ABI.System.ComponentModel.DataErrorsChangedEventArgs), "Microsoft.UI.Xaml.Data.DataErrorsChangedEventArgs", isRuntimeClass: true); + RegisterCustomAbiTypeMappingNoLock(typeof(PropertyChangedEventArgs), typeof(ABI.System.ComponentModel.PropertyChangedEventArgs), "Microsoft.UI.Xaml.Data.PropertyChangedEventArgs", isRuntimeClass: true); + RegisterCustomAbiTypeMappingNoLock(typeof(PropertyChangedEventHandler), typeof(ABI.System.ComponentModel.PropertyChangedEventHandler), "Microsoft.UI.Xaml.Data.PropertyChangedEventHandler"); + RegisterCustomAbiTypeMappingNoLock(typeof(INotifyDataErrorInfo), typeof(ABI.System.ComponentModel.INotifyDataErrorInfo), "Microsoft.UI.Xaml.Data.INotifyDataErrorInfo"); + RegisterCustomAbiTypeMappingNoLock(typeof(INotifyPropertyChanged), typeof(ABI.System.ComponentModel.INotifyPropertyChanged), "Microsoft.UI.Xaml.Data.INotifyPropertyChanged"); + RegisterCustomAbiTypeMappingNoLock(typeof(ICommand), typeof(ABI.System.Windows.Input.ICommand), "Microsoft.UI.Xaml.Input.ICommand"); + RegisterCustomAbiTypeMappingNoLock(typeof(IServiceProvider), typeof(ABI.System.IServiceProvider), "Microsoft.UI.Xaml.IXamlServiceProvider"); + RegisterCustomAbiTypeMappingNoLock(typeof(IEnumerable), typeof(ABI.System.Collections.IEnumerable), "Microsoft.UI.Xaml.Interop.IBindableIterable"); + RegisterCustomAbiTypeMappingNoLock(typeof(IList), typeof(ABI.System.Collections.IList), "Microsoft.UI.Xaml.Interop.IBindableVector"); + RegisterCustomAbiTypeMappingNoLock(typeof(INotifyCollectionChanged), typeof(ABI.System.Collections.Specialized.INotifyCollectionChanged), "Microsoft.UI.Xaml.Interop.INotifyCollectionChanged"); + RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedAction), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedAction), "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction"); + RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedEventArgs), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs), "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", isRuntimeClass: true); + RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedEventHandler), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler), "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventHandler"); + } + else + { + RegisterCustomAbiTypeMappingNoLock(typeof(PropertyChangedEventArgs), typeof(ABI.System.ComponentModel.PropertyChangedEventArgs), "Windows.UI.Xaml.Data.PropertyChangedEventArgs", isRuntimeClass: true); + RegisterCustomAbiTypeMappingNoLock(typeof(PropertyChangedEventHandler), typeof(ABI.System.ComponentModel.PropertyChangedEventHandler), "Windows.UI.Xaml.Data.PropertyChangedEventHandler"); + RegisterCustomAbiTypeMappingNoLock(typeof(INotifyPropertyChanged), typeof(ABI.System.ComponentModel.INotifyPropertyChanged), "Windows.UI.Xaml.Data.INotifyPropertyChanged"); + RegisterCustomAbiTypeMappingNoLock(typeof(ICommand), typeof(ABI.System.Windows.Input.ICommand), "Windows.UI.Xaml.Interop.ICommand"); + RegisterCustomAbiTypeMappingNoLock(typeof(IEnumerable), typeof(ABI.System.Collections.IEnumerable), "Windows.UI.Xaml.Interop.IBindableIterable"); + RegisterCustomAbiTypeMappingNoLock(typeof(IList), typeof(ABI.System.Collections.IList), "Windows.UI.Xaml.Interop.IBindableVector"); + RegisterCustomAbiTypeMappingNoLock(typeof(INotifyCollectionChanged), typeof(ABI.System.Collections.Specialized.INotifyCollectionChanged), "Windows.UI.Xaml.Interop.INotifyCollectionChanged"); + RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedAction), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedAction), "Windows.UI.Xaml.Interop.NotifyCollectionChangedAction"); + RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedEventArgs), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs), "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", isRuntimeClass: true); + RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedEventHandler), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler), "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler"); + } + RegisterCustomAbiTypeMappingNoLock(typeof(EventHandler<>), typeof(ABI.System.EventHandler<>), "Windows.Foundation.EventHandler`1"); RegisterCustomAbiTypeMappingNoLock(typeof(KeyValuePair<,>), typeof(ABI.System.Collections.Generic.KeyValuePair<,>), "Windows.Foundation.Collections.IKeyValuePair`2"); @@ -83,12 +117,6 @@ static Projections() RegisterCustomAbiTypeMappingNoLock(typeof(IReadOnlyDictionary<,>), typeof(ABI.System.Collections.Generic.IReadOnlyDictionary<,>), "Windows.Foundation.Collections.IMapView`2"); RegisterCustomAbiTypeMappingNoLock(typeof(IDisposable), typeof(ABI.System.IDisposable), "Windows.Foundation.IClosable"); - RegisterCustomAbiTypeMappingNoLock(typeof(IEnumerable), typeof(ABI.System.Collections.IEnumerable), "Microsoft.UI.Xaml.Interop.IBindableIterable"); - RegisterCustomAbiTypeMappingNoLock(typeof(IList), typeof(ABI.System.Collections.IList), "Microsoft.UI.Xaml.Interop.IBindableVector"); - RegisterCustomAbiTypeMappingNoLock(typeof(INotifyCollectionChanged), typeof(ABI.System.Collections.Specialized.INotifyCollectionChanged), "Microsoft.UI.Xaml.Interop.INotifyCollectionChanged"); - RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedAction), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedAction), "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction"); - RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedEventArgs), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs), "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", isRuntimeClass: true); - RegisterCustomAbiTypeMappingNoLock(typeof(NotifyCollectionChangedEventHandler), typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler), "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventHandler"); RegisterCustomAbiTypeMappingNoLock(typeof(Matrix3x2), typeof(ABI.System.Numerics.Matrix3x2), "Windows.Foundation.Numerics.Matrix3x2"); RegisterCustomAbiTypeMappingNoLock(typeof(Matrix4x4), typeof(ABI.System.Numerics.Matrix4x4), "Windows.Foundation.Numerics.Matrix4x4"); @@ -105,6 +133,7 @@ static Projections() RegisterCustomTypeToHelperTypeMappingNoLock(typeof(IVector<>), typeof(ABI.System.Collections.Generic.IList<>)); RegisterCustomTypeToHelperTypeMappingNoLock(typeof(IMapView<,>), typeof(ABI.System.Collections.Generic.IReadOnlyDictionary<,>)); RegisterCustomTypeToHelperTypeMappingNoLock(typeof(IVectorView<>), typeof(ABI.System.Collections.Generic.IReadOnlyList<>)); + // The IBindable* types have the same IID on both MUX and WUX, so we can use the same type in both scenarios. RegisterCustomTypeToHelperTypeMappingNoLock(typeof(Microsoft.UI.Xaml.Interop.IBindableVector), typeof(ABI.System.Collections.IList)); #if NET diff --git a/src/WinRT.Runtime/Projections/ICommand.net5.cs b/src/WinRT.Runtime/Projections/ICommand.net5.cs index 7f7308629..4fe21ab2f 100644 --- a/src/WinRT.Runtime/Projections/ICommand.net5.cs +++ b/src/WinRT.Runtime/Projections/ICommand.net5.cs @@ -74,6 +74,7 @@ public static unsafe EventHandlerEventSource Get_CanExecuteChanged2(IObjectRefer } } + // ICommand has the same IID for both Windows.UI.Xaml.Input.ICommand and Microsoft.UI.Xaml.Input.ICommand, so we can use one interface definition for both without marking it as a WUX/MUX type. [EditorBrowsable(EditorBrowsableState.Never)] [Guid("E5AF3542-CA67-4081-995B-709DD13792DF")] [DynamicInterfaceCastableImplementation] diff --git a/src/WinRT.Runtime/Projections/ICustomPropertyProvider.net5.cs b/src/WinRT.Runtime/Projections/ICustomPropertyProvider.net5.cs index cd63ce463..b982623e9 100644 --- a/src/WinRT.Runtime/Projections/ICustomPropertyProvider.net5.cs +++ b/src/WinRT.Runtime/Projections/ICustomPropertyProvider.net5.cs @@ -6,6 +6,8 @@ using System.Runtime.InteropServices; using WinRT; +// These types have the same GUIDs in both Microsoft.UI.Xaml and Windows.UI.Xaml, +// so we don't need to duplicate them for the internal usage here as they can be transparently used by both WUX and MUX. namespace Microsoft.UI.Xaml.Data { [global::WinRT.WindowsRuntimeType] diff --git a/src/WinRT.Runtime/Projections/INotifyCollectionChanged.net5.cs b/src/WinRT.Runtime/Projections/INotifyCollectionChanged.net5.cs index 5370dceba..b812db480 100644 --- a/src/WinRT.Runtime/Projections/INotifyCollectionChanged.net5.cs +++ b/src/WinRT.Runtime/Projections/INotifyCollectionChanged.net5.cs @@ -3,8 +3,10 @@ using System; using System.ComponentModel; +using System.Reflection; using System.Runtime.InteropServices; using WinRT; +using WinRT.Interop; namespace ABI.System.Collections.Specialized { @@ -35,7 +37,9 @@ static class INotifyCollectionChangedMethods }); } - public static global::System.Guid IID => global::WinRT.Interop.IID.IID_INotifyCollectionChanged; + public static global::System.Guid IID => FeatureSwitches.UseWindowsUIXamlProjections + ? global::WinRT.Interop.IID.IID_WUX_INotifyCollectionChanged + : global::WinRT.Interop.IID.IID_MUX_INotifyCollectionChanged; public static IntPtr AbiToProjectionVftablePtr => INotifyCollectionChanged.Vftbl.AbiToProjectionVftablePtr; } @@ -43,6 +47,7 @@ static class INotifyCollectionChangedMethods [DynamicInterfaceCastableImplementation] [EditorBrowsable(EditorBrowsableState.Never)] [Guid("530155E1-28A5-5693-87CE-30724D95A06D")] + [WuxMuxProjectedType] internal unsafe interface INotifyCollectionChanged : global::System.Collections.Specialized.INotifyCollectionChanged { [Guid("530155E1-28A5-5693-87CE-30724D95A06D")] @@ -121,7 +126,6 @@ private static unsafe int Do_Abi_remove_CollectionChanged_1(IntPtr thisPtr, glob } } } - internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr, global::WinRT.Interop.IID.IID_INotifyCollectionChanged); private static global::ABI.WinRT.Interop.EventSource _CollectionChanged(IWinRTObject _this) { diff --git a/src/WinRT.Runtime/Projections/INotifyPropertyChanged.net5.cs b/src/WinRT.Runtime/Projections/INotifyPropertyChanged.net5.cs index ff411bfe5..1b72b7de9 100644 --- a/src/WinRT.Runtime/Projections/INotifyPropertyChanged.net5.cs +++ b/src/WinRT.Runtime/Projections/INotifyPropertyChanged.net5.cs @@ -4,20 +4,23 @@ using System; using System.Runtime.InteropServices; using WinRT; +using WinRT.Interop; namespace ABI.System.ComponentModel -{ +{ #if EMBED internal #else public #endif static class INotifyPropertyChangedMethods - { - public static global::System.Guid IID => global::WinRT.Interop.IID.IID_INotifyPropertyChanged; + { + public static global::System.Guid IID => FeatureSwitches.UseWindowsUIXamlProjections + ? global::WinRT.Interop.IID.IID_WUX_INotifyPropertyChanged + : global::WinRT.Interop.IID.IID_MUX_INotifyPropertyChanged; + + public static IntPtr AbiToProjectionVftablePtr => INotifyPropertyChanged.Vftbl.AbiToProjectionVftablePtr; - public static IntPtr AbiToProjectionVftablePtr => INotifyPropertyChanged.Vftbl.AbiToProjectionVftablePtr; - private volatile static global::System.Runtime.CompilerServices.ConditionalWeakTable _PropertyChanged; private static global::System.Runtime.CompilerServices.ConditionalWeakTable MakePropertyChangedTable() { @@ -25,7 +28,7 @@ static class INotifyPropertyChangedMethods return _PropertyChanged; } private static global::System.Runtime.CompilerServices.ConditionalWeakTable PropertyChanged => _PropertyChanged ?? MakePropertyChangedTable(); - + public static unsafe global::ABI.WinRT.Interop.EventSource Get_PropertyChanged2(IObjectReference obj, object thisObj) { return PropertyChanged.GetValue(thisObj, (key) => @@ -41,14 +44,16 @@ static class INotifyPropertyChangedMethods [DynamicInterfaceCastableImplementation] [Guid("90B17601-B065-586E-83D9-9ADC3A695284")] + [WuxMuxProjectedType] internal unsafe interface INotifyPropertyChanged : global::System.ComponentModel.INotifyPropertyChanged { +#pragma warning disable CA2257 [Guid("90B17601-B065-586E-83D9-9ADC3A695284")] - [StructLayout(LayoutKind.Sequential)] -#pragma warning disable CA2257 // This member is a type (so it cannot be invoked) - public struct Vftbl + [StructLayout(LayoutKind.Sequential)] + public struct Vftbl #pragma warning restore CA2257 { + internal IInspectable.Vftbl IInspectableVftbl; private delegate* unmanaged _add_PropertyChanged_0; @@ -119,11 +124,10 @@ private static unsafe int Do_Abi_remove_PropertyChanged_1(IntPtr thisPtr, global } } } - internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr, global::WinRT.Interop.IID.IID_INotifyPropertyChanged); private static global::ABI.WinRT.Interop.EventSource _PropertyChanged(IWinRTObject _this) { - var _obj = _this.GetObjectReferenceForType(typeof(global::System.ComponentModel.INotifyPropertyChanged).TypeHandle); + var _obj = _this.GetObjectReferenceForType(typeof(global::System.ComponentModel.INotifyPropertyChanged).TypeHandle); return INotifyPropertyChangedMethods.Get_PropertyChanged2(_obj, _this); } diff --git a/src/WinRT.Runtime/Projections/NotifyCollectionChangedAction.cs b/src/WinRT.Runtime/Projections/NotifyCollectionChangedAction.cs index b6ccf1bc7..dccf0cc49 100644 --- a/src/WinRT.Runtime/Projections/NotifyCollectionChangedAction.cs +++ b/src/WinRT.Runtime/Projections/NotifyCollectionChangedAction.cs @@ -1,10 +1,15 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using WinRT; + namespace ABI.System.Collections.Specialized { static class NotifyCollectionChangedAction { - public static string GetGuidSignature() => "enum(Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction;i4)"; + public static string GetGuidSignature() => + FeatureSwitches.UseWindowsUIXamlProjections + ? "enum(Windows.UI.Xaml.Interop.NotifyCollectionChangedAction;i4)" + : "enum(Microsoft.UI.Xaml.Interop.NotifyCollectionChangedAction;i4)"; } } diff --git a/src/WinRT.Runtime/Projections/NotifyCollectionChangedEventArgs.cs b/src/WinRT.Runtime/Projections/NotifyCollectionChangedEventArgs.cs index 728a81fff..5cb24a1e6 100644 --- a/src/WinRT.Runtime/Projections/NotifyCollectionChangedEventArgs.cs +++ b/src/WinRT.Runtime/Projections/NotifyCollectionChangedEventArgs.cs @@ -1,89 +1,96 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using ABI.Microsoft.UI.Xaml.Interop; -using System; -using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using WinRT; -using WinRT.Interop; - -namespace ABI.Microsoft.UI.Xaml.Interop -{ +// Licensed under the MIT License. + +using ABI.Microsoft.UI.Xaml.Interop; +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using WinRT; +using WinRT.Interop; + +namespace ABI.Microsoft.UI.Xaml.Interop +{ #if !NET [global::WinRT.ObjectReferenceWrapper(nameof(_obj))] -#endif - [Guid("5108EBA4-4892-5A20-8374-A96815E0FD27")] - internal sealed unsafe class WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory - { - private readonly IObjectReference _obj; - public IntPtr ThisPtr => _obj.ThisPtr; - - public static readonly WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory Instance = new(); - - private WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory() +#endif + [Guid("5108EBA4-4892-5A20-8374-A96815E0FD27")] + internal sealed unsafe class WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory + { + private readonly IObjectReference _obj; + public IntPtr ThisPtr => _obj.ThisPtr; + + public static readonly WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory Instance = new(); + + private WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory() + { +#if NET + _obj = FeatureSwitches.UseWindowsUIXamlProjections + ? ActivationFactory.Get("Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", IID.IID_WUX_INotifyCollectionChangedEventArgsFactory) + : ActivationFactory.Get("Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", IID.IID_MUX_INotifyCollectionChangedEventArgsFactory); +#else + _obj = ActivationFactory.Get("Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", IID.IID_MUX_INotifyCollectionChangedEventArgsFactory); +#endif + } + + public unsafe ObjectReferenceValue CreateInstanceWithAllParameters(global::System.Collections.Specialized.NotifyCollectionChangedAction action, global::System.Collections.IList newItems, global::System.Collections.IList oldItems, int newIndex, int oldIndex) { -#if NET - _obj = ActivationFactory.Get("Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", IID.IID_INotifyCollectionChangedEventArgsFactory); -#else - _obj = ActivationFactory.Get("Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", IID.IID_INotifyCollectionChangedEventArgsFactory); -#endif - } - - public unsafe ObjectReferenceValue CreateInstanceWithAllParameters(global::System.Collections.Specialized.NotifyCollectionChangedAction action, global::System.Collections.IList newItems, global::System.Collections.IList oldItems, int newIndex, int oldIndex) - { - ObjectReferenceValue __newItems = default; - ObjectReferenceValue __oldItems = default; - IntPtr __innerInterface = default; - IntPtr __retval = default; - try + ObjectReferenceValue __newItems = default; + ObjectReferenceValue __oldItems = default; + IntPtr __innerInterface = default; + IntPtr __retval = default; + try { -#if NET - __newItems = MarshalInterface.CreateMarshaler2(newItems, global::ABI.System.Collections.IListMethods.IID); +#if NET + __newItems = MarshalInterface.CreateMarshaler2(newItems, global::ABI.System.Collections.IListMethods.IID); __oldItems = MarshalInterface.CreateMarshaler2(oldItems, global::ABI.System.Collections.IListMethods.IID); -#else - __newItems = MarshalInterface.CreateMarshaler2(newItems); - __oldItems = MarshalInterface.CreateMarshaler2(oldItems); -#endif - global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[6]( - ThisPtr, - action, - MarshalInterface.GetAbi(__newItems), - MarshalInterface.GetAbi(__oldItems), - newIndex, - oldIndex, - IntPtr.Zero, - &__innerInterface, - &__retval)); - return new ObjectReferenceValue(__retval); - } - finally - { - __newItems.Dispose(); - __oldItems.Dispose(); - MarshalInspectable.DisposeAbi(__innerInterface); - } - } - } -} - -namespace ABI.System.Collections.Specialized -{ - [EditorBrowsable(EditorBrowsableState.Never)] - [StructLayout(LayoutKind.Sequential)] -#if EMBED - internal -#else - public -#endif - struct NotifyCollectionChangedEventArgs +#else + __newItems = MarshalInterface.CreateMarshaler2(newItems); + __oldItems = MarshalInterface.CreateMarshaler2(oldItems); +#endif + global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[6]( + ThisPtr, + action, + MarshalInterface.GetAbi(__newItems), + MarshalInterface.GetAbi(__oldItems), + newIndex, + oldIndex, + IntPtr.Zero, + &__innerInterface, + &__retval)); + return new ObjectReferenceValue(__retval); + } + finally + { + __newItems.Dispose(); + __oldItems.Dispose(); + MarshalInspectable.DisposeAbi(__innerInterface); + } + } + } +} + +namespace ABI.System.Collections.Specialized +{ + [EditorBrowsable(EditorBrowsableState.Never)] + [StructLayout(LayoutKind.Sequential)] + [WuxMuxProjectedType] +#if EMBED + internal +#else + public +#endif + struct NotifyCollectionChangedEventArgs { - public static IObjectReference CreateMarshaler(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs value) - { - if (value is null) - { - return null; + private static ref readonly Guid Interface_IID => ref FeatureSwitches.UseWindowsUIXamlProjections + ? ref IID.IID_WUX_INotifyCollectionChangedEventArgs + : ref IID.IID_MUX_INotifyCollectionChangedEventArgs; + + public static IObjectReference CreateMarshaler(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs value) + { + if (value is null) + { + return null; } ObjectReferenceValue _value = default; @@ -98,26 +105,26 @@ public static IObjectReference CreateMarshaler(global::System.Collections.Specia } } - public static ObjectReferenceValue CreateMarshaler2(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs value) - { - if (value is null) - { - return new ObjectReferenceValue(); - } - - return WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory.Instance.CreateInstanceWithAllParameters(value.Action, value.NewItems, value.OldItems, value.NewStartingIndex, value.OldStartingIndex); - } - - public static IntPtr GetAbi(IObjectReference m) => m?.ThisPtr ?? IntPtr.Zero; - - public static global::System.Collections.Specialized.NotifyCollectionChangedEventArgs FromAbi(IntPtr ptr) - { - if (ptr == IntPtr.Zero) - { - return null; - } - - return CreateNotifyCollectionChangedEventArgs(ptr); + public static ObjectReferenceValue CreateMarshaler2(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs value) + { + if (value is null) + { + return new ObjectReferenceValue(); + } + + return WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory.Instance.CreateInstanceWithAllParameters(value.Action, value.NewItems, value.OldItems, value.NewStartingIndex, value.OldStartingIndex); + } + + public static IntPtr GetAbi(IObjectReference m) => m?.ThisPtr ?? IntPtr.Zero; + + public static global::System.Collections.Specialized.NotifyCollectionChangedEventArgs FromAbi(IntPtr ptr) + { + if (ptr == IntPtr.Zero) + { + return null; + } + + return CreateNotifyCollectionChangedEventArgs(ptr); } private static unsafe global::System.Collections.Specialized.NotifyCollectionChangedEventArgs CreateNotifyCollectionChangedEventArgs(IntPtr ptr) @@ -132,7 +139,7 @@ public static ObjectReferenceValue CreateMarshaler2(global::System.Collections.S try { // Call can come from CreateObject which means it might not be on the right interface. - global::WinRT.ExceptionHelpers.ThrowExceptionForHR(Marshal.QueryInterface(ptr, ref Unsafe.AsRef(in IID.IID_INotifyCollectionChangedEventArgs), out thisPtr)); + global::WinRT.ExceptionHelpers.ThrowExceptionForHR(Marshal.QueryInterface(ptr, ref Unsafe.AsRef(in Interface_IID), out thisPtr)); global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)thisPtr)[6](thisPtr, &action)); global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)thisPtr)[7](thisPtr, &newItems)); @@ -152,52 +159,56 @@ public static ObjectReferenceValue CreateMarshaler2(global::System.Collections.S MarshalInterface.DisposeAbi(oldItems); Marshal.Release(thisPtr); } - } - - private static global::System.Collections.Specialized.NotifyCollectionChangedEventArgs CreateNotifyCollectionChangedEventArgs( - global::System.Collections.Specialized.NotifyCollectionChangedAction action, - global::System.Collections.IList newItems, - global::System.Collections.IList oldItems, - int newStartingIndex, - int oldStartingIndex) => - action switch - { - global::System.Collections.Specialized.NotifyCollectionChangedAction.Add => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(action, newItems, newStartingIndex), - global::System.Collections.Specialized.NotifyCollectionChangedAction.Remove => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(action, oldItems, oldStartingIndex), - global::System.Collections.Specialized.NotifyCollectionChangedAction.Replace => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(action, newItems, oldItems, newStartingIndex), - global::System.Collections.Specialized.NotifyCollectionChangedAction.Move => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(action, newItems, newStartingIndex, oldStartingIndex), - global::System.Collections.Specialized.NotifyCollectionChangedAction.Reset => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(global::System.Collections.Specialized.NotifyCollectionChangedAction.Reset), - _ => throw new ArgumentException(), - }; - - public static unsafe void CopyManaged(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs o, IntPtr dest) - { - *(IntPtr*)dest.ToPointer() = CreateMarshaler2(o).Detach(); - } - - public static IntPtr FromManaged(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs value) - { - if (value is null) - { - return IntPtr.Zero; - } - return CreateMarshaler2(value).Detach(); - } - - public static void DisposeMarshaler(IObjectReference m) { m?.Dispose(); } + } + + private static global::System.Collections.Specialized.NotifyCollectionChangedEventArgs CreateNotifyCollectionChangedEventArgs( + global::System.Collections.Specialized.NotifyCollectionChangedAction action, + global::System.Collections.IList newItems, + global::System.Collections.IList oldItems, + int newStartingIndex, + int oldStartingIndex) => + action switch + { + global::System.Collections.Specialized.NotifyCollectionChangedAction.Add => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(action, newItems, newStartingIndex), + global::System.Collections.Specialized.NotifyCollectionChangedAction.Remove => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(action, oldItems, oldStartingIndex), + global::System.Collections.Specialized.NotifyCollectionChangedAction.Replace => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(action, newItems, oldItems, newStartingIndex), + global::System.Collections.Specialized.NotifyCollectionChangedAction.Move => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(action, newItems, newStartingIndex, oldStartingIndex), + global::System.Collections.Specialized.NotifyCollectionChangedAction.Reset => new global::System.Collections.Specialized.NotifyCollectionChangedEventArgs(global::System.Collections.Specialized.NotifyCollectionChangedAction.Reset), + _ => throw new ArgumentException(), + }; + + public static unsafe void CopyManaged(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs o, IntPtr dest) + { + *(IntPtr*)dest.ToPointer() = CreateMarshaler2(o).Detach(); + } + + public static IntPtr FromManaged(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs value) + { + if (value is null) + { + return IntPtr.Zero; + } + return CreateMarshaler2(value).Detach(); + } + + public static void DisposeMarshaler(IObjectReference m) { m?.Dispose(); } public static void DisposeAbi(IntPtr abi) { MarshalInspectable.DisposeAbi(abi); } - public static unsafe MarshalInterfaceHelper.MarshalerArray CreateMarshalerArray(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs[] array) => MarshalInterfaceHelper.CreateMarshalerArray2(array, CreateMarshaler2); - public static (int length, IntPtr data) GetAbiArray(object box) => MarshalInterfaceHelper.GetAbiArray(box); - public static unsafe global::System.Collections.Specialized.NotifyCollectionChangedEventArgs[] FromAbiArray(object box) => MarshalInterfaceHelper.FromAbiArray(box, FromAbi); - public static void CopyAbiArray(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs[] array, object box) => MarshalInterfaceHelper.CopyAbiArray(array, box, FromAbi); - public static (int length, IntPtr data) FromManagedArray(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs[] array) => MarshalInterfaceHelper.FromManagedArray(array, FromManaged); - public static void DisposeMarshalerArray(MarshalInterfaceHelper.MarshalerArray array) => MarshalInterfaceHelper.DisposeMarshalerArray(array); - public static unsafe void DisposeAbiArray(object box) => MarshalInspectable.DisposeAbiArray(box); - - public static string GetGuidSignature() - { - return "rc(Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs;{4cf68d33-e3f2-4964-b85e-945b4f7e2f21})"; - } - } -} + public static unsafe MarshalInterfaceHelper.MarshalerArray CreateMarshalerArray(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs[] array) => MarshalInterfaceHelper.CreateMarshalerArray2(array, CreateMarshaler2); + public static (int length, IntPtr data) GetAbiArray(object box) => MarshalInterfaceHelper.GetAbiArray(box); + public static unsafe global::System.Collections.Specialized.NotifyCollectionChangedEventArgs[] FromAbiArray(object box) => MarshalInterfaceHelper.FromAbiArray(box, FromAbi); + public static void CopyAbiArray(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs[] array, object box) => MarshalInterfaceHelper.CopyAbiArray(array, box, FromAbi); + public static (int length, IntPtr data) FromManagedArray(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs[] array) => MarshalInterfaceHelper.FromManagedArray(array, FromManaged); + public static void DisposeMarshalerArray(MarshalInterfaceHelper.MarshalerArray array) => MarshalInterfaceHelper.DisposeMarshalerArray(array); + public static unsafe void DisposeAbiArray(object box) => MarshalInspectable.DisposeAbiArray(box); + + public static string GetGuidSignature() + { + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + return "rc(Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs;{4cf68d33-e3f2-4964-b85e-945b4f7e2f21})"; + } + return "rc(Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs;{4cf68d33-e3f2-4964-b85e-945b4f7e2f21})"; + } + } +} diff --git a/src/WinRT.Runtime/Projections/NotifyCollectionChangedEventHandler.cs b/src/WinRT.Runtime/Projections/NotifyCollectionChangedEventHandler.cs index 05a433e46..18333338d 100644 --- a/src/WinRT.Runtime/Projections/NotifyCollectionChangedEventHandler.cs +++ b/src/WinRT.Runtime/Projections/NotifyCollectionChangedEventHandler.cs @@ -1,202 +1,205 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using WinRT; -using WinRT.Interop; - -namespace ABI.System.Collections.Specialized -{ - - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - [Guid("8B0909DC-2005-5D93-BF8A-725F017BAA8D")] -#if EMBED - internal -#else - public -#endif - static class NotifyCollectionChangedEventHandler - { -#if !NET - private unsafe delegate int Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e); -#endif - - private static readonly global::WinRT.Interop.IDelegateVftbl AbiToProjectionVftable; - public static readonly IntPtr AbiToProjectionVftablePtr; - - static unsafe NotifyCollectionChangedEventHandler() - { - AbiToProjectionVftable = new global::WinRT.Interop.IDelegateVftbl - { - IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl, -#if !NET - Invoke = Marshal.GetFunctionPointerForDelegate(AbiInvokeDelegate = (Abi_Invoke)Do_Abi_Invoke) -#else - Invoke = (IntPtr)(delegate* unmanaged[Stdcall])&Do_Abi_Invoke -#endif - }; - var nativeVftbl = ComWrappersSupport.AllocateVtableMemory(typeof(NotifyCollectionChangedEventHandler), sizeof(global::WinRT.Interop.IDelegateVftbl)); - *(global::WinRT.Interop.IDelegateVftbl*)nativeVftbl = AbiToProjectionVftable; - AbiToProjectionVftablePtr = nativeVftbl; - ComWrappersSupport.RegisterDelegateFactory(typeof(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler), CreateRcw); - } - - public static global::System.Delegate AbiInvokeDelegate { get; } - - public static Guid IID => global::WinRT.Interop.IID.IID_NotifyCollectionChangedEventHandler; - - public static unsafe IObjectReference CreateMarshaler(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler managedDelegate) => - managedDelegate is null ? null : MarshalDelegate.CreateMarshaler(managedDelegate, IID); - - public static unsafe ObjectReferenceValue CreateMarshaler2(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler managedDelegate) => - MarshalDelegate.CreateMarshaler2(managedDelegate, IID); - - public static IntPtr GetAbi(IObjectReference value) => MarshalInterfaceHelper.GetAbi(value); - - public static unsafe global::System.Collections.Specialized.NotifyCollectionChangedEventHandler FromAbi(IntPtr nativeDelegate) - { - return MarshalDelegate.FromAbi(nativeDelegate); - } - - public static global::System.Collections.Specialized.NotifyCollectionChangedEventHandler CreateRcw(IntPtr ptr) - { - return new global::System.Collections.Specialized.NotifyCollectionChangedEventHandler(new NativeDelegateWrapper(ComWrappersSupport.GetObjectReferenceForInterface(ptr, IID)).Invoke); - } - -#if !NET - [global::WinRT.ObjectReferenceWrapper(nameof(_nativeDelegate))] - private sealed class NativeDelegateWrapper -#else - private sealed class NativeDelegateWrapper : IWinRTObject -#endif - { - private readonly ObjectReference _nativeDelegate; - - public NativeDelegateWrapper(ObjectReference nativeDelegate) - { - _nativeDelegate = nativeDelegate; - } - -#if NET - IObjectReference IWinRTObject.NativeObject => _nativeDelegate; - bool IWinRTObject.HasUnwrappableNativeObject => true; - private volatile ConcurrentDictionary _queryInterfaceCache; - private ConcurrentDictionary MakeQueryInterfaceCache() - { - global::System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new ConcurrentDictionary(), null); - return _queryInterfaceCache; - } - ConcurrentDictionary IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache(); - - private volatile ConcurrentDictionary _additionalTypeData; - private ConcurrentDictionary MakeAdditionalTypeData() - { - global::System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new ConcurrentDictionary(), null); - return _additionalTypeData; - } - ConcurrentDictionary IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData(); -#endif - - public unsafe void Invoke(object sender, global::System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - IntPtr ThisPtr = _nativeDelegate.ThisPtr; -#if !NET - var abiInvoke = Marshal.GetDelegateForFunctionPointer(_nativeDelegate.Vftbl.Invoke); -#else - var abiInvoke = (delegate* unmanaged[Stdcall])(_nativeDelegate.Vftbl.Invoke); -#endif - ObjectReferenceValue __sender = default; - ObjectReferenceValue __e = default; - try - { - __sender = MarshalInspectable.CreateMarshaler2(sender); - __e = global::ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs.CreateMarshaler2(e); - global::WinRT.ExceptionHelpers.ThrowExceptionForHR(abiInvoke(ThisPtr, MarshalInspectable.GetAbi(__sender), MarshalInspectable.GetAbi(__e))); - } - finally - { - MarshalInspectable.DisposeMarshaler(__sender); - MarshalInspectable.DisposeMarshaler(__e); - } - - } - } - - public static IntPtr FromManaged(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler managedDelegate) => - CreateMarshaler2(managedDelegate).Detach(); - - public static void DisposeMarshaler(IObjectReference value) => MarshalInterfaceHelper.DisposeMarshaler(value); - - public static void DisposeAbi(IntPtr abi) => MarshalInterfaceHelper.DisposeAbi(abi); - - public static unsafe MarshalInterfaceHelper.MarshalerArray CreateMarshalerArray(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler[] array) => MarshalInterfaceHelper.CreateMarshalerArray2(array, CreateMarshaler2); - public static (int length, IntPtr data) GetAbiArray(object box) => MarshalInterfaceHelper.GetAbiArray(box); - public static unsafe global::System.Collections.Specialized.NotifyCollectionChangedEventHandler[] FromAbiArray(object box) => MarshalInterfaceHelper.FromAbiArray(box, FromAbi); - public static void CopyAbiArray(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler[] array, object box) => MarshalInterfaceHelper.CopyAbiArray(array, box, FromAbi); - public static (int length, IntPtr data) FromManagedArray(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler[] array) => MarshalInterfaceHelper.FromManagedArray(array, FromManaged); - public static void DisposeMarshalerArray(MarshalInterfaceHelper.MarshalerArray array) => MarshalInterfaceHelper.DisposeMarshalerArray(array); - public static unsafe void DisposeAbiArray(object box) => MarshalInspectable.DisposeAbiArray(box); - -#if NET - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] -#endif - private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e) - { - try - { -#if NET - var invoke = ComWrappersSupport.FindObject(thisPtr); - invoke.Invoke(MarshalInspectable.FromAbi(sender), global::ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs.FromAbi(e)); -#else - global::WinRT.ComWrappersSupport.MarshalDelegateInvoke(thisPtr, (global::System.Collections.Specialized.NotifyCollectionChangedEventHandler invoke) => - { - invoke(MarshalInspectable.FromAbi(sender), global::ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs.FromAbi(e)); - }); -#endif - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - - internal sealed unsafe class NotifyCollectionChangedEventHandlerEventSource : global::ABI.WinRT.Interop.EventSource - { - internal NotifyCollectionChangedEventHandlerEventSource( - IObjectReference objectReference, -#if NET - delegate* unmanaged[Stdcall] addHandler, -#else - delegate* unmanaged[Stdcall] addHandler, -#endif - delegate* unmanaged[Stdcall] removeHandler) - : base(objectReference, addHandler, removeHandler) - { - } - - protected override ObjectReferenceValue CreateMarshaler(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler del) => - NotifyCollectionChangedEventHandler.CreateMarshaler2(del); - - protected override global::ABI.WinRT.Interop.EventSourceState CreateEventSourceState() => - new EventState(ObjectReference.ThisPtr, Index); - - private sealed class EventState : global::ABI.WinRT.Interop.EventSourceState - { - public EventState(IntPtr obj, int index) - : base(obj, index) - { - } - - protected override global::System.Collections.Specialized.NotifyCollectionChangedEventHandler GetEventInvoke() - { - return (obj, e) => targetDelegate?.Invoke(obj, e); - } - } - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using WinRT; +using WinRT.Interop; + +namespace ABI.System.Collections.Specialized +{ + + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + [Guid("8B0909DC-2005-5D93-BF8A-725F017BAA8D")] + [WuxMuxProjectedType] +#if EMBED + internal +#else + public +#endif + static class NotifyCollectionChangedEventHandler + { +#if !NET + private unsafe delegate int Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e); +#endif + + private static readonly global::WinRT.Interop.IDelegateVftbl AbiToProjectionVftable; + public static readonly IntPtr AbiToProjectionVftablePtr; + + static unsafe NotifyCollectionChangedEventHandler() + { + AbiToProjectionVftable = new global::WinRT.Interop.IDelegateVftbl + { + IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl, +#if !NET + Invoke = Marshal.GetFunctionPointerForDelegate(AbiInvokeDelegate = (Abi_Invoke)Do_Abi_Invoke) +#else + Invoke = (IntPtr)(delegate* unmanaged[Stdcall])&Do_Abi_Invoke +#endif + }; + var nativeVftbl = ComWrappersSupport.AllocateVtableMemory(typeof(NotifyCollectionChangedEventHandler), sizeof(global::WinRT.Interop.IDelegateVftbl)); + *(global::WinRT.Interop.IDelegateVftbl*)nativeVftbl = AbiToProjectionVftable; + AbiToProjectionVftablePtr = nativeVftbl; + ComWrappersSupport.RegisterDelegateFactory(typeof(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler), CreateRcw); + } + + public static global::System.Delegate AbiInvokeDelegate { get; } + + public static Guid IID => FeatureSwitches.UseWindowsUIXamlProjections + ? global::WinRT.Interop.IID.IID_WUX_NotifyCollectionChangedEventHandler + : global::WinRT.Interop.IID.IID_MUX_NotifyCollectionChangedEventHandler; + + public static unsafe IObjectReference CreateMarshaler(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler managedDelegate) => + managedDelegate is null ? null : MarshalDelegate.CreateMarshaler(managedDelegate, IID); + + public static unsafe ObjectReferenceValue CreateMarshaler2(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler managedDelegate) => + MarshalDelegate.CreateMarshaler2(managedDelegate, IID); + + public static IntPtr GetAbi(IObjectReference value) => MarshalInterfaceHelper.GetAbi(value); + + public static unsafe global::System.Collections.Specialized.NotifyCollectionChangedEventHandler FromAbi(IntPtr nativeDelegate) + { + return MarshalDelegate.FromAbi(nativeDelegate); + } + + public static global::System.Collections.Specialized.NotifyCollectionChangedEventHandler CreateRcw(IntPtr ptr) + { + return new global::System.Collections.Specialized.NotifyCollectionChangedEventHandler(new NativeDelegateWrapper(ComWrappersSupport.GetObjectReferenceForInterface(ptr, IID)).Invoke); + } + +#if !NET + [global::WinRT.ObjectReferenceWrapper(nameof(_nativeDelegate))] + private sealed class NativeDelegateWrapper +#else + private sealed class NativeDelegateWrapper : IWinRTObject +#endif + { + private readonly ObjectReference _nativeDelegate; + + public NativeDelegateWrapper(ObjectReference nativeDelegate) + { + _nativeDelegate = nativeDelegate; + } + +#if NET + IObjectReference IWinRTObject.NativeObject => _nativeDelegate; + bool IWinRTObject.HasUnwrappableNativeObject => true; + private volatile ConcurrentDictionary _queryInterfaceCache; + private ConcurrentDictionary MakeQueryInterfaceCache() + { + global::System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new ConcurrentDictionary(), null); + return _queryInterfaceCache; + } + ConcurrentDictionary IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache(); + + private volatile ConcurrentDictionary _additionalTypeData; + private ConcurrentDictionary MakeAdditionalTypeData() + { + global::System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new ConcurrentDictionary(), null); + return _additionalTypeData; + } + ConcurrentDictionary IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData(); +#endif + + public unsafe void Invoke(object sender, global::System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + IntPtr ThisPtr = _nativeDelegate.ThisPtr; +#if !NET + var abiInvoke = Marshal.GetDelegateForFunctionPointer(_nativeDelegate.Vftbl.Invoke); +#else + var abiInvoke = (delegate* unmanaged[Stdcall])(_nativeDelegate.Vftbl.Invoke); +#endif + ObjectReferenceValue __sender = default; + ObjectReferenceValue __e = default; + try + { + __sender = MarshalInspectable.CreateMarshaler2(sender); + __e = global::ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs.CreateMarshaler2(e); + global::WinRT.ExceptionHelpers.ThrowExceptionForHR(abiInvoke(ThisPtr, MarshalInspectable.GetAbi(__sender), MarshalInspectable.GetAbi(__e))); + } + finally + { + MarshalInspectable.DisposeMarshaler(__sender); + MarshalInspectable.DisposeMarshaler(__e); + } + + } + } + + public static IntPtr FromManaged(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler managedDelegate) => + CreateMarshaler2(managedDelegate).Detach(); + + public static void DisposeMarshaler(IObjectReference value) => MarshalInterfaceHelper.DisposeMarshaler(value); + + public static void DisposeAbi(IntPtr abi) => MarshalInterfaceHelper.DisposeAbi(abi); + + public static unsafe MarshalInterfaceHelper.MarshalerArray CreateMarshalerArray(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler[] array) => MarshalInterfaceHelper.CreateMarshalerArray2(array, CreateMarshaler2); + public static (int length, IntPtr data) GetAbiArray(object box) => MarshalInterfaceHelper.GetAbiArray(box); + public static unsafe global::System.Collections.Specialized.NotifyCollectionChangedEventHandler[] FromAbiArray(object box) => MarshalInterfaceHelper.FromAbiArray(box, FromAbi); + public static void CopyAbiArray(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler[] array, object box) => MarshalInterfaceHelper.CopyAbiArray(array, box, FromAbi); + public static (int length, IntPtr data) FromManagedArray(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler[] array) => MarshalInterfaceHelper.FromManagedArray(array, FromManaged); + public static void DisposeMarshalerArray(MarshalInterfaceHelper.MarshalerArray array) => MarshalInterfaceHelper.DisposeMarshalerArray(array); + public static unsafe void DisposeAbiArray(object box) => MarshalInspectable.DisposeAbiArray(box); + +#if NET + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] +#endif + private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e) + { + try + { +#if NET + var invoke = ComWrappersSupport.FindObject(thisPtr); + invoke.Invoke(MarshalInspectable.FromAbi(sender), global::ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs.FromAbi(e)); +#else + global::WinRT.ComWrappersSupport.MarshalDelegateInvoke(thisPtr, (global::System.Collections.Specialized.NotifyCollectionChangedEventHandler invoke) => + { + invoke(MarshalInspectable.FromAbi(sender), global::ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs.FromAbi(e)); + }); +#endif + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + + internal sealed unsafe class NotifyCollectionChangedEventHandlerEventSource : global::ABI.WinRT.Interop.EventSource + { + internal NotifyCollectionChangedEventHandlerEventSource( + IObjectReference objectReference, +#if NET + delegate* unmanaged[Stdcall] addHandler, +#else + delegate* unmanaged[Stdcall] addHandler, +#endif + delegate* unmanaged[Stdcall] removeHandler) + : base(objectReference, addHandler, removeHandler) + { + } + + protected override ObjectReferenceValue CreateMarshaler(global::System.Collections.Specialized.NotifyCollectionChangedEventHandler del) => + NotifyCollectionChangedEventHandler.CreateMarshaler2(del); + + protected override global::ABI.WinRT.Interop.EventSourceState CreateEventSourceState() => + new EventState(ObjectReference.ThisPtr, Index); + + private sealed class EventState : global::ABI.WinRT.Interop.EventSourceState + { + public EventState(IntPtr obj, int index) + : base(obj, index) + { + } + + protected override global::System.Collections.Specialized.NotifyCollectionChangedEventHandler GetEventInvoke() + { + return (obj, e) => targetDelegate?.Invoke(obj, e); + } + } + } +} diff --git a/src/WinRT.Runtime/Projections/PropertyChangedEventArgs.cs b/src/WinRT.Runtime/Projections/PropertyChangedEventArgs.cs index 5273edb40..61116de9d 100644 --- a/src/WinRT.Runtime/Projections/PropertyChangedEventArgs.cs +++ b/src/WinRT.Runtime/Projections/PropertyChangedEventArgs.cs @@ -1,175 +1,177 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.ComponentModel; -using System.Runtime.InteropServices; -using WinRT; -using WinRT.Interop; - -namespace ABI.Microsoft.UI.Xaml.Data -{ - [Guid("63D0C952-396B-54F4-AF8C-BA8724A427BF")] - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct IPropertyChangedEventArgsVftbl - { - internal IInspectable.Vftbl IInspectableVftbl; - private void* _get_PropertyName_0; - public delegate* unmanaged[Stdcall] get_PropertyName_0 => (delegate* unmanaged[Stdcall])_get_PropertyName_0; - } - -#if !NET - [global::WinRT.ObjectReferenceWrapper(nameof(_obj))] -#endif - [Guid("7C0C27A8-0B41-5070-B160-FC9AE960A36C")] - internal sealed unsafe class WinRTPropertyChangedEventArgsRuntimeClassFactory - { - [Guid("7C0C27A8-0B41-5070-B160-FC9AE960A36C")] - [StructLayout(LayoutKind.Sequential)] - public struct Vftbl - { - internal IInspectable.Vftbl IInspectableVftbl; - private void* _CreateInstance_0; - public delegate* unmanaged[Stdcall] CreateInstance_0 => (delegate* unmanaged[Stdcall])_CreateInstance_0; - } - public static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr, global::WinRT.Interop.IID.IID_PropertyChangedEventArgsRuntimeClassFactory); - - private readonly ObjectReference _obj; - public IntPtr ThisPtr => _obj.ThisPtr; - public WinRTPropertyChangedEventArgsRuntimeClassFactory(IObjectReference obj) : this(obj.As(IID.IID_PropertyChangedEventArgsRuntimeClassFactory)) { } - public WinRTPropertyChangedEventArgsRuntimeClassFactory(ObjectReference obj) - { - _obj = obj; - } - - public unsafe IObjectReference CreateInstance(string name, object baseInterface, out IObjectReference innerInterface) - { - IObjectReference __baseInterface = default; - IntPtr __innerInterface = default; - IntPtr __retval = default; - try - { - MarshalString.Pinnable __name = new(name); - fixed (void* ___name = __name) - { - __baseInterface = MarshalInspectable.CreateMarshaler(baseInterface); - global::WinRT.ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.CreateInstance_0(ThisPtr, MarshalString.GetAbi(ref __name), MarshalInspectable.GetAbi(__baseInterface), &__innerInterface, &__retval)); - innerInterface = ObjectReference.FromAbi(__innerInterface, IID.IID_IUnknown); - return ObjectReference.Attach(ref __retval, IID.IID_IUnknown); - } - } - finally - { - MarshalInspectable.DisposeMarshaler(__baseInterface); - MarshalInspectable.DisposeAbi(__innerInterface); - MarshalInspectable.DisposeAbi(__retval); - } - } - - public unsafe ObjectReferenceValue CreateInstance(string name) - { - IntPtr __innerInterface = default; - IntPtr __retval = default; - try - { - MarshalString.Pinnable __name = new(name); - fixed (void* ___name = __name) - { - global::WinRT.ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.CreateInstance_0(ThisPtr, MarshalString.GetAbi(ref __name), IntPtr.Zero, &__innerInterface, &__retval)); - return new ObjectReferenceValue(__retval); - } - } - finally - { - MarshalInspectable.DisposeAbi(__innerInterface); - } - } - - } -} - -namespace ABI.System.ComponentModel -{ - [EditorBrowsable(EditorBrowsableState.Never)] - [StructLayout(LayoutKind.Sequential)] -#if EMBED - internal -#else - public -#endif - unsafe struct PropertyChangedEventArgs - { - private static readonly ABI.Microsoft.UI.Xaml.Data.WinRTPropertyChangedEventArgsRuntimeClassFactory Instance = new(ActivationFactory.Get("Microsoft.UI.Xaml.Data.PropertyChangedEventArgs")); - - public static IObjectReference CreateMarshaler(global::System.ComponentModel.PropertyChangedEventArgs value) - { - if (value is null) - { - return null; - } - - return Instance.CreateInstance(value.PropertyName, null, out _); - } - - public static ObjectReferenceValue CreateMarshaler2(global::System.ComponentModel.PropertyChangedEventArgs value) - { - if (value is null) - { - return new ObjectReferenceValue(); - } - - return Instance.CreateInstance(value.PropertyName); - } - - public static IntPtr GetAbi(IObjectReference m) => m?.ThisPtr ?? IntPtr.Zero; - - public static global::System.ComponentModel.PropertyChangedEventArgs FromAbi(IntPtr ptr) - { - if (ptr == IntPtr.Zero) - { - return null; - } - - IntPtr propertyName = IntPtr.Zero; - try - { - ExceptionHelpers.ThrowExceptionForHR((**(ABI.Microsoft.UI.Xaml.Data.IPropertyChangedEventArgsVftbl**)ptr).get_PropertyName_0(ptr, &propertyName)); - return new global::System.ComponentModel.PropertyChangedEventArgs(MarshalString.FromAbi(propertyName)); - } - finally - { - MarshalString.DisposeAbi(propertyName); - } - } - - public static unsafe void CopyManaged(global::System.ComponentModel.PropertyChangedEventArgs o, IntPtr dest) - { - *(IntPtr*)dest.ToPointer() = CreateMarshaler2(o).Detach(); - } - - public static IntPtr FromManaged(global::System.ComponentModel.PropertyChangedEventArgs value) - { - if (value is null) - { - return IntPtr.Zero; - } - return CreateMarshaler2(value).Detach(); - } - - public static void DisposeMarshaler(IObjectReference m) { m?.Dispose(); } - public static void DisposeAbi(IntPtr abi) { MarshalInspectable.DisposeAbi(abi); } - - public static unsafe MarshalInterfaceHelper.MarshalerArray CreateMarshalerArray(global::System.ComponentModel.PropertyChangedEventArgs[] array) => MarshalInterfaceHelper.CreateMarshalerArray2(array, CreateMarshaler2); - public static (int length, IntPtr data) GetAbiArray(object box) => MarshalInterfaceHelper.GetAbiArray(box); - public static unsafe global::System.ComponentModel.PropertyChangedEventArgs[] FromAbiArray(object box) => MarshalInterfaceHelper.FromAbiArray(box, FromAbi); - public static void CopyAbiArray(global::System.ComponentModel.PropertyChangedEventArgs[] array, object box) => MarshalInterfaceHelper.CopyAbiArray(array, box, FromAbi); - public static (int length, IntPtr data) FromManagedArray(global::System.ComponentModel.PropertyChangedEventArgs[] array) => MarshalInterfaceHelper.FromManagedArray(array, FromManaged); - public static void DisposeMarshalerArray(MarshalInterfaceHelper.MarshalerArray array) => MarshalInterfaceHelper.DisposeMarshalerArray(array); - public static unsafe void DisposeAbiArray(object box) => MarshalInspectable.DisposeAbiArray(box); - - public static string GetGuidSignature() - { - return "rc(Microsoft.UI.Xaml.Data.NotifyPropertyChangedEventArgs;{4f33a9a0-5cf4-47a4-b16f-d7faaf17457e})"; - } - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using WinRT; +using WinRT.Interop; + +namespace ABI.Microsoft.UI.Xaml.Data +{ + internal sealed unsafe class PropertyChangedEventArgsRuntimeClassFactory + { + private readonly IObjectReference _obj; + + public PropertyChangedEventArgsRuntimeClassFactory() + { +#if NET + _obj = FeatureSwitches.UseWindowsUIXamlProjections + ? ActivationFactory.Get("Windows.UI.Xaml.Data.PropertyChangedEventArgs", IID.IID_WUX_PropertyChangedEventArgsRuntimeClassFactory) + : ActivationFactory.Get("Microsoft.UI.Xaml.Data.PropertyChangedEventArgs", IID.IID_MUX_PropertyChangedEventArgsRuntimeClassFactory); +#else + _obj = ActivationFactory.Get("Microsoft.UI.Xaml.Data.PropertyChangedEventArgs", IID.IID_MUX_PropertyChangedEventArgsRuntimeClassFactory); +#endif + } + + public IObjectReference CreateInstance(string name, object baseInterface, out IObjectReference innerInterface) + { + IObjectReference __baseInterface = default; + IntPtr __innerInterface = default; + IntPtr __retval = default; + try + { + MarshalString.Pinnable __name = new(name); + fixed (void* ___name = __name) + { + __baseInterface = MarshalInspectable.CreateMarshaler(baseInterface); + IntPtr thisPtr = _obj.ThisPtr; + global::WinRT.ExceptionHelpers.ThrowExceptionForHR( + ((delegate* unmanaged[Stdcall])(*(void***)thisPtr)[6])( + thisPtr, + MarshalString.GetAbi(ref __name), + MarshalInspectable.GetAbi(__baseInterface), + &__innerInterface, + &__retval)); + innerInterface = ObjectReference.FromAbi(__innerInterface, IID.IID_IUnknown); + return ObjectReference.Attach(ref __retval, IID.IID_IUnknown); + } + } + finally + { + MarshalInspectable.DisposeMarshaler(__baseInterface); + MarshalInspectable.DisposeAbi(__innerInterface); + MarshalInspectable.DisposeAbi(__retval); + } + } + + public ObjectReferenceValue CreateInstance(string name) + { + IntPtr __innerInterface = default; + IntPtr __retval = default; + try + { + MarshalString.Pinnable __name = new(name); + fixed (void* ___name = __name) + { + IntPtr thisPtr = _obj.ThisPtr; + global::WinRT.ExceptionHelpers.ThrowExceptionForHR( + ((delegate* unmanaged[Stdcall])(*(void***)thisPtr)[6])( + thisPtr, + MarshalString.GetAbi(ref __name), + IntPtr.Zero, + &__innerInterface, + &__retval)); + return new ObjectReferenceValue(__retval); + } + } + finally + { + MarshalInspectable.DisposeAbi(__innerInterface); + } + } + } +} + +namespace ABI.System.ComponentModel +{ + [EditorBrowsable(EditorBrowsableState.Never)] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + unsafe struct PropertyChangedEventArgs + { + private static readonly ABI.Microsoft.UI.Xaml.Data.PropertyChangedEventArgsRuntimeClassFactory Instance = new(); + + public static IObjectReference CreateMarshaler(global::System.ComponentModel.PropertyChangedEventArgs value) + { + if (value is null) + { + return null; + } + + return Instance.CreateInstance(value.PropertyName, null, out _); + } + + public static ObjectReferenceValue CreateMarshaler2(global::System.ComponentModel.PropertyChangedEventArgs value) + { + if (value is null) + { + return new ObjectReferenceValue(); + } + + return Instance.CreateInstance(value.PropertyName); + } + + public static IntPtr GetAbi(IObjectReference m) => m?.ThisPtr ?? IntPtr.Zero; + + public static global::System.ComponentModel.PropertyChangedEventArgs FromAbi(IntPtr ptr) + { + if (ptr == IntPtr.Zero) + { + return null; + } + + IntPtr propertyName = IntPtr.Zero; + try + { + // We can use the Microsoft.UI.Xaml.Data.IPropertyChangedEventArgsVftbl here in both WUX and MUX because the vtables are laid out the same and we know + // that we have either a MUX or WUX IPropertyChangedEventArgs pointer in ptr. + ExceptionHelpers.ThrowExceptionForHR(((delegate* unmanaged[Stdcall])(*(void***)ptr)[6])(ptr, &propertyName)); + return new global::System.ComponentModel.PropertyChangedEventArgs(MarshalString.FromAbi(propertyName)); + } + finally + { + MarshalString.DisposeAbi(propertyName); + } + } + + public static unsafe void CopyManaged(global::System.ComponentModel.PropertyChangedEventArgs o, IntPtr dest) + { + *(IntPtr*)dest.ToPointer() = CreateMarshaler2(o).Detach(); + } + + public static IntPtr FromManaged(global::System.ComponentModel.PropertyChangedEventArgs value) + { + if (value is null) + { + return IntPtr.Zero; + } + return CreateMarshaler2(value).Detach(); + } + + public static void DisposeMarshaler(IObjectReference m) { m?.Dispose(); } + public static void DisposeAbi(IntPtr abi) { MarshalInspectable.DisposeAbi(abi); } + + public static unsafe MarshalInterfaceHelper.MarshalerArray CreateMarshalerArray(global::System.ComponentModel.PropertyChangedEventArgs[] array) => MarshalInterfaceHelper.CreateMarshalerArray2(array, CreateMarshaler2); + public static (int length, IntPtr data) GetAbiArray(object box) => MarshalInterfaceHelper.GetAbiArray(box); + public static unsafe global::System.ComponentModel.PropertyChangedEventArgs[] FromAbiArray(object box) => MarshalInterfaceHelper.FromAbiArray(box, FromAbi); + public static void CopyAbiArray(global::System.ComponentModel.PropertyChangedEventArgs[] array, object box) => MarshalInterfaceHelper.CopyAbiArray(array, box, FromAbi); + public static (int length, IntPtr data) FromManagedArray(global::System.ComponentModel.PropertyChangedEventArgs[] array) => MarshalInterfaceHelper.FromManagedArray(array, FromManaged); + public static void DisposeMarshalerArray(MarshalInterfaceHelper.MarshalerArray array) => MarshalInterfaceHelper.DisposeMarshalerArray(array); + public static unsafe void DisposeAbiArray(object box) => MarshalInspectable.DisposeAbiArray(box); + + public static string GetGuidSignature() + { + if (FeatureSwitches.UseWindowsUIXamlProjections) + { + return "rc(Windows.UI.Xaml.Data.NotifyPropertyChangedEventArgs;{4f33a9a0-5cf4-47a4-b16f-d7faaf17457e})"; + } + + return "rc(Microsoft.UI.Xaml.Data.NotifyPropertyChangedEventArgs;{4f33a9a0-5cf4-47a4-b16f-d7faaf17457e})"; + } + } +} diff --git a/src/WinRT.Runtime/Projections/PropertyChangedEventHandler.cs b/src/WinRT.Runtime/Projections/PropertyChangedEventHandler.cs index a38b988ea..9d821c102 100644 --- a/src/WinRT.Runtime/Projections/PropertyChangedEventHandler.cs +++ b/src/WinRT.Runtime/Projections/PropertyChangedEventHandler.cs @@ -1,200 +1,203 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using WinRT; -using WinRT.Interop; - -namespace ABI.System.ComponentModel -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - [Guid("E3DE52F6-1E32-5DA6-BB2D-B5B6096C962D")] -#if EMBED - internal -#else - public -#endif - static class PropertyChangedEventHandler - { -#if !NET - private unsafe delegate int Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e); -#endif - - private static readonly global::WinRT.Interop.IDelegateVftbl AbiToProjectionVftable; - public static readonly IntPtr AbiToProjectionVftablePtr; - - static unsafe PropertyChangedEventHandler() - { - AbiToProjectionVftable = new global::WinRT.Interop.IDelegateVftbl - { - IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl, -#if !NET - Invoke = Marshal.GetFunctionPointerForDelegate(AbiInvokeDelegate = (Abi_Invoke)Do_Abi_Invoke) -#else - Invoke = (IntPtr)(delegate* unmanaged[Stdcall])&Do_Abi_Invoke -#endif - }; - var nativeVftbl = ComWrappersSupport.AllocateVtableMemory(typeof(PropertyChangedEventHandler), sizeof(global::WinRT.Interop.IDelegateVftbl)); - *(IDelegateVftbl*)nativeVftbl = AbiToProjectionVftable; - AbiToProjectionVftablePtr = nativeVftbl; - ComWrappersSupport.RegisterDelegateFactory(typeof(global::System.ComponentModel.PropertyChangedEventHandler), CreateRcw); - } - - public static global::System.Delegate AbiInvokeDelegate { get; } - - public static Guid IID => global::WinRT.Interop.IID.IID_PropertyChangedEventHandler; - - public static unsafe IObjectReference CreateMarshaler(global::System.ComponentModel.PropertyChangedEventHandler managedDelegate) => - managedDelegate is null ? null : MarshalDelegate.CreateMarshaler(managedDelegate, IID); - - public static unsafe ObjectReferenceValue CreateMarshaler2(global::System.ComponentModel.PropertyChangedEventHandler managedDelegate) => - MarshalDelegate.CreateMarshaler2(managedDelegate, IID); - - public static IntPtr GetAbi(IObjectReference value) => MarshalInterfaceHelper.GetAbi(value); - - public static unsafe global::System.ComponentModel.PropertyChangedEventHandler FromAbi(IntPtr nativeDelegate) - { - return MarshalDelegate.FromAbi(nativeDelegate); - } - - public static global::System.ComponentModel.PropertyChangedEventHandler CreateRcw(IntPtr ptr) - { - return new global::System.ComponentModel.PropertyChangedEventHandler(new NativeDelegateWrapper(ComWrappersSupport.GetObjectReferenceForInterface(ptr, IID)).Invoke); - } - -#if !NET - [global::WinRT.ObjectReferenceWrapper(nameof(_nativeDelegate))] - private sealed class NativeDelegateWrapper -#else - private sealed class NativeDelegateWrapper : IWinRTObject -#endif - { - private readonly ObjectReference _nativeDelegate; - - public NativeDelegateWrapper(ObjectReference nativeDelegate) - { - _nativeDelegate = nativeDelegate; - } - -#if NET - IObjectReference IWinRTObject.NativeObject => _nativeDelegate; - bool IWinRTObject.HasUnwrappableNativeObject => true; - private volatile ConcurrentDictionary _queryInterfaceCache; - private ConcurrentDictionary MakeQueryInterfaceCache() - { - global::System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new ConcurrentDictionary(), null); - return _queryInterfaceCache; - } - ConcurrentDictionary IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache(); - - private volatile ConcurrentDictionary _additionalTypeData; - private ConcurrentDictionary MakeAdditionalTypeData() - { - global::System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new ConcurrentDictionary(), null); - return _additionalTypeData; - } - ConcurrentDictionary IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData(); -#endif - - public unsafe void Invoke(object sender, global::System.ComponentModel.PropertyChangedEventArgs e) - { - IntPtr ThisPtr = _nativeDelegate.ThisPtr; -#if !NET - var abiInvoke = Marshal.GetDelegateForFunctionPointer(_nativeDelegate.Vftbl.Invoke); -#else - var abiInvoke = (delegate* unmanaged[Stdcall])(_nativeDelegate.Vftbl.Invoke); -#endif - ObjectReferenceValue __sender = default; - ObjectReferenceValue __e = default; - try - { - __sender = MarshalInspectable.CreateMarshaler2(sender); - __e = global::ABI.System.ComponentModel.PropertyChangedEventArgs.CreateMarshaler2(e); - global::WinRT.ExceptionHelpers.ThrowExceptionForHR(abiInvoke(ThisPtr, MarshalInspectable.GetAbi(__sender), MarshalInspectable.GetAbi(__e))); - } - finally - { - MarshalInspectable.DisposeMarshaler(__sender); - MarshalInspectable.DisposeMarshaler(__e); - } - } - } - - public static IntPtr FromManaged(global::System.ComponentModel.PropertyChangedEventHandler managedDelegate) => - CreateMarshaler2(managedDelegate).Detach(); - - public static void DisposeMarshaler(IObjectReference value) => MarshalInterfaceHelper.DisposeMarshaler(value); - - public static void DisposeAbi(IntPtr abi) => MarshalInterfaceHelper.DisposeAbi(abi); - - public static unsafe MarshalInterfaceHelper.MarshalerArray CreateMarshalerArray(global::System.ComponentModel.PropertyChangedEventHandler[] array) => MarshalInterfaceHelper.CreateMarshalerArray2(array, CreateMarshaler2); - public static (int length, IntPtr data) GetAbiArray(object box) => MarshalInterfaceHelper.GetAbiArray(box); - public static unsafe global::System.ComponentModel.PropertyChangedEventHandler[] FromAbiArray(object box) => MarshalInterfaceHelper.FromAbiArray(box, FromAbi); - public static void CopyAbiArray(global::System.ComponentModel.PropertyChangedEventHandler[] array, object box) => MarshalInterfaceHelper.CopyAbiArray(array, box, FromAbi); - public static (int length, IntPtr data) FromManagedArray(global::System.ComponentModel.PropertyChangedEventHandler[] array) => MarshalInterfaceHelper.FromManagedArray(array, FromManaged); - public static void DisposeMarshalerArray(MarshalInterfaceHelper.MarshalerArray array) => MarshalInterfaceHelper.DisposeMarshalerArray(array); - public static unsafe void DisposeAbiArray(object box) => MarshalInspectable.DisposeAbiArray(box); - -#if NET - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] -#endif - private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e) - { - try - { -#if NET - var invoke = ComWrappersSupport.FindObject(thisPtr); - invoke.Invoke(MarshalInspectable.FromAbi(sender), global::ABI.System.ComponentModel.PropertyChangedEventArgs.FromAbi(e)); -#else - global::WinRT.ComWrappersSupport.MarshalDelegateInvoke(thisPtr, (global::System.ComponentModel.PropertyChangedEventHandler invoke) => - { - invoke(MarshalInspectable.FromAbi(sender), global::ABI.System.ComponentModel.PropertyChangedEventArgs.FromAbi(e)); - }); -#endif - } - catch (global::System.Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - - internal sealed unsafe class PropertyChangedEventSource : global::ABI.WinRT.Interop.EventSource - { - internal PropertyChangedEventSource( - IObjectReference objectReference, -#if NET - delegate* unmanaged[Stdcall] addHandler, -#else - delegate* unmanaged[Stdcall] addHandler, -#endif - delegate* unmanaged[Stdcall] removeHandler) - : base(objectReference, addHandler, removeHandler) - { - } - - protected override ObjectReferenceValue CreateMarshaler(global::System.ComponentModel.PropertyChangedEventHandler del) => - PropertyChangedEventHandler.CreateMarshaler2(del); - - protected override global::ABI.WinRT.Interop.EventSourceState CreateEventSourceState() => - new EventState(ObjectReference.ThisPtr, Index); - - private sealed class EventState : global::ABI.WinRT.Interop.EventSourceState - { - public EventState(IntPtr obj, int index) - : base(obj, index) - { - } - - protected override global::System.ComponentModel.PropertyChangedEventHandler GetEventInvoke() - { - return (obj, e) => targetDelegate?.Invoke(obj, e); - } - } - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using WinRT; +using WinRT.Interop; + +namespace ABI.System.ComponentModel +{ + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + [Guid("E3DE52F6-1E32-5DA6-BB2D-B5B6096C962D")] + [WuxMuxProjectedType] +#if EMBED + internal +#else + public +#endif + static class PropertyChangedEventHandler + { +#if !NET + private unsafe delegate int Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e); +#endif + + private static readonly global::WinRT.Interop.IDelegateVftbl AbiToProjectionVftable; + public static readonly IntPtr AbiToProjectionVftablePtr; + + static unsafe PropertyChangedEventHandler() + { + AbiToProjectionVftable = new global::WinRT.Interop.IDelegateVftbl + { + IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl, +#if !NET + Invoke = Marshal.GetFunctionPointerForDelegate(AbiInvokeDelegate = (Abi_Invoke)Do_Abi_Invoke) +#else + Invoke = (IntPtr)(delegate* unmanaged[Stdcall])&Do_Abi_Invoke +#endif + }; + var nativeVftbl = ComWrappersSupport.AllocateVtableMemory(typeof(PropertyChangedEventHandler), sizeof(global::WinRT.Interop.IDelegateVftbl)); + *(IDelegateVftbl*)nativeVftbl = AbiToProjectionVftable; + AbiToProjectionVftablePtr = nativeVftbl; + ComWrappersSupport.RegisterDelegateFactory(typeof(global::System.ComponentModel.PropertyChangedEventHandler), CreateRcw); + } + + public static global::System.Delegate AbiInvokeDelegate { get; } + + public static Guid IID => FeatureSwitches.UseWindowsUIXamlProjections + ? global::WinRT.Interop.IID.IID_WUX_PropertyChangedEventHandler + : global::WinRT.Interop.IID.IID_MUX_PropertyChangedEventHandler; + + public static unsafe IObjectReference CreateMarshaler(global::System.ComponentModel.PropertyChangedEventHandler managedDelegate) => + managedDelegate is null ? null : MarshalDelegate.CreateMarshaler(managedDelegate, IID); + + public static unsafe ObjectReferenceValue CreateMarshaler2(global::System.ComponentModel.PropertyChangedEventHandler managedDelegate) => + MarshalDelegate.CreateMarshaler2(managedDelegate, IID); + + public static IntPtr GetAbi(IObjectReference value) => MarshalInterfaceHelper.GetAbi(value); + + public static unsafe global::System.ComponentModel.PropertyChangedEventHandler FromAbi(IntPtr nativeDelegate) + { + return MarshalDelegate.FromAbi(nativeDelegate); + } + + public static global::System.ComponentModel.PropertyChangedEventHandler CreateRcw(IntPtr ptr) + { + return new global::System.ComponentModel.PropertyChangedEventHandler(new NativeDelegateWrapper(ComWrappersSupport.GetObjectReferenceForInterface(ptr, IID)).Invoke); + } + +#if !NET + [global::WinRT.ObjectReferenceWrapper(nameof(_nativeDelegate))] + private sealed class NativeDelegateWrapper +#else + private sealed class NativeDelegateWrapper : IWinRTObject +#endif + { + private readonly ObjectReference _nativeDelegate; + + public NativeDelegateWrapper(ObjectReference nativeDelegate) + { + _nativeDelegate = nativeDelegate; + } + +#if NET + IObjectReference IWinRTObject.NativeObject => _nativeDelegate; + bool IWinRTObject.HasUnwrappableNativeObject => true; + private volatile ConcurrentDictionary _queryInterfaceCache; + private ConcurrentDictionary MakeQueryInterfaceCache() + { + global::System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new ConcurrentDictionary(), null); + return _queryInterfaceCache; + } + ConcurrentDictionary IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache(); + + private volatile ConcurrentDictionary _additionalTypeData; + private ConcurrentDictionary MakeAdditionalTypeData() + { + global::System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new ConcurrentDictionary(), null); + return _additionalTypeData; + } + ConcurrentDictionary IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData(); +#endif + + public unsafe void Invoke(object sender, global::System.ComponentModel.PropertyChangedEventArgs e) + { + IntPtr ThisPtr = _nativeDelegate.ThisPtr; +#if !NET + var abiInvoke = Marshal.GetDelegateForFunctionPointer(_nativeDelegate.Vftbl.Invoke); +#else + var abiInvoke = (delegate* unmanaged[Stdcall])(_nativeDelegate.Vftbl.Invoke); +#endif + ObjectReferenceValue __sender = default; + ObjectReferenceValue __e = default; + try + { + __sender = MarshalInspectable.CreateMarshaler2(sender); + __e = global::ABI.System.ComponentModel.PropertyChangedEventArgs.CreateMarshaler2(e); + global::WinRT.ExceptionHelpers.ThrowExceptionForHR(abiInvoke(ThisPtr, MarshalInspectable.GetAbi(__sender), MarshalInspectable.GetAbi(__e))); + } + finally + { + MarshalInspectable.DisposeMarshaler(__sender); + MarshalInspectable.DisposeMarshaler(__e); + } + } + } + + public static IntPtr FromManaged(global::System.ComponentModel.PropertyChangedEventHandler managedDelegate) => + CreateMarshaler2(managedDelegate).Detach(); + + public static void DisposeMarshaler(IObjectReference value) => MarshalInterfaceHelper.DisposeMarshaler(value); + + public static void DisposeAbi(IntPtr abi) => MarshalInterfaceHelper.DisposeAbi(abi); + + public static unsafe MarshalInterfaceHelper.MarshalerArray CreateMarshalerArray(global::System.ComponentModel.PropertyChangedEventHandler[] array) => MarshalInterfaceHelper.CreateMarshalerArray2(array, CreateMarshaler2); + public static (int length, IntPtr data) GetAbiArray(object box) => MarshalInterfaceHelper.GetAbiArray(box); + public static unsafe global::System.ComponentModel.PropertyChangedEventHandler[] FromAbiArray(object box) => MarshalInterfaceHelper.FromAbiArray(box, FromAbi); + public static void CopyAbiArray(global::System.ComponentModel.PropertyChangedEventHandler[] array, object box) => MarshalInterfaceHelper.CopyAbiArray(array, box, FromAbi); + public static (int length, IntPtr data) FromManagedArray(global::System.ComponentModel.PropertyChangedEventHandler[] array) => MarshalInterfaceHelper.FromManagedArray(array, FromManaged); + public static void DisposeMarshalerArray(MarshalInterfaceHelper.MarshalerArray array) => MarshalInterfaceHelper.DisposeMarshalerArray(array); + public static unsafe void DisposeAbiArray(object box) => MarshalInspectable.DisposeAbiArray(box); + +#if NET + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })] +#endif + private static unsafe int Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e) + { + try + { +#if NET + var invoke = ComWrappersSupport.FindObject(thisPtr); + invoke.Invoke(MarshalInspectable.FromAbi(sender), global::ABI.System.ComponentModel.PropertyChangedEventArgs.FromAbi(e)); +#else + global::WinRT.ComWrappersSupport.MarshalDelegateInvoke(thisPtr, (global::System.ComponentModel.PropertyChangedEventHandler invoke) => + { + invoke(MarshalInspectable.FromAbi(sender), global::ABI.System.ComponentModel.PropertyChangedEventArgs.FromAbi(e)); + }); +#endif + } + catch (global::System.Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + + internal sealed unsafe class PropertyChangedEventSource : global::ABI.WinRT.Interop.EventSource + { + internal PropertyChangedEventSource( + IObjectReference objectReference, +#if NET + delegate* unmanaged[Stdcall] addHandler, +#else + delegate* unmanaged[Stdcall] addHandler, +#endif + delegate* unmanaged[Stdcall] removeHandler) + : base(objectReference, addHandler, removeHandler) + { + } + + protected override ObjectReferenceValue CreateMarshaler(global::System.ComponentModel.PropertyChangedEventHandler del) => + PropertyChangedEventHandler.CreateMarshaler2(del); + + protected override global::ABI.WinRT.Interop.EventSourceState CreateEventSourceState() => + new EventState(ObjectReference.ThisPtr, Index); + + private sealed class EventState : global::ABI.WinRT.Interop.EventSourceState + { + public EventState(IntPtr obj, int index) + : base(obj, index) + { + } + + protected override global::System.ComponentModel.PropertyChangedEventHandler GetEventInvoke() + { + return (obj, e) => targetDelegate?.Invoke(obj, e); + } + } + } +} diff --git a/src/cswinrt.sln b/src/cswinrt.sln index bdc0d86a0..e6bb53157 100644 --- a/src/cswinrt.sln +++ b/src/cswinrt.sln @@ -160,6 +160,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinAppSDK", "Projections\Wi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLibrary", "Tests\FunctionalTests\TestLibrary\TestLibrary.csproj", "{335D51AC-1DCF-4487-A2BD-34CE2F17B3C4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Windows.UI.Xaml", "Projections\Windows.UI.Xaml\Windows.UI.Xaml.csproj", "{E85F3614-79B6-4652-BDB0-64AF68874CE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthoringWuxTest", "Tests\AuthoringWuxTest\AuthoringWuxTest.csproj", "{D60CFCAD-4A13-4047-91C8-9D7DF4753493}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AuthoringWuxConsumptionTest", "Tests\AuthoringWuxConsumptionTest\AuthoringWuxConsumptionTest.vcxproj", "{A04A0416-5E35-4DD0-8226-63D941B28467}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -732,6 +738,54 @@ Global {335D51AC-1DCF-4487-A2BD-34CE2F17B3C4}.Release|x64.Build.0 = Release|x64 {335D51AC-1DCF-4487-A2BD-34CE2F17B3C4}.Release|x86.ActiveCfg = Release|x86 {335D51AC-1DCF-4487-A2BD-34CE2F17B3C4}.Release|x86.Build.0 = Release|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Debug|ARM.ActiveCfg = Debug|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Debug|ARM.Build.0 = Debug|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Debug|ARM64.ActiveCfg = Debug|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Debug|ARM64.Build.0 = Debug|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Debug|x64.ActiveCfg = Debug|x64 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Debug|x64.Build.0 = Debug|x64 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Debug|x86.ActiveCfg = Debug|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Debug|x86.Build.0 = Debug|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Release|ARM.ActiveCfg = Release|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Release|ARM.Build.0 = Release|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Release|ARM64.ActiveCfg = Release|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Release|ARM64.Build.0 = Release|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Release|x64.ActiveCfg = Release|x64 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Release|x64.Build.0 = Release|x64 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Release|x86.ActiveCfg = Release|x86 + {E85F3614-79B6-4652-BDB0-64AF68874CE0}.Release|x86.Build.0 = Release|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Debug|ARM.ActiveCfg = Debug|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Debug|ARM.Build.0 = Debug|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Debug|ARM64.ActiveCfg = Debug|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Debug|ARM64.Build.0 = Debug|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Debug|x64.ActiveCfg = Debug|x64 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Debug|x64.Build.0 = Debug|x64 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Debug|x86.ActiveCfg = Debug|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Debug|x86.Build.0 = Debug|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Release|ARM.ActiveCfg = Release|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Release|ARM.Build.0 = Release|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Release|ARM64.ActiveCfg = Release|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Release|ARM64.Build.0 = Release|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Release|x64.ActiveCfg = Release|x64 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Release|x64.Build.0 = Release|x64 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Release|x86.ActiveCfg = Release|x86 + {D60CFCAD-4A13-4047-91C8-9D7DF4753493}.Release|x86.Build.0 = Release|x86 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Debug|ARM.ActiveCfg = Debug|Win32 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Debug|ARM.Build.0 = Debug|Win32 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Debug|ARM64.Build.0 = Debug|ARM64 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Debug|x64.ActiveCfg = Debug|x64 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Debug|x64.Build.0 = Debug|x64 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Debug|x86.ActiveCfg = Debug|Win32 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Debug|x86.Build.0 = Debug|Win32 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Release|ARM.ActiveCfg = Release|Win32 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Release|ARM.Build.0 = Release|Win32 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Release|ARM64.ActiveCfg = Release|ARM64 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Release|ARM64.Build.0 = Release|ARM64 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Release|x64.ActiveCfg = Release|x64 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Release|x64.Build.0 = Release|x64 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Release|x86.ActiveCfg = Release|Win32 + {A04A0416-5E35-4DD0-8226-63D941B28467}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -777,6 +831,9 @@ Global {C44DB047-5DF0-4732-98F4-A181D3AD8A7F} = {5ECC38F0-16FD-47E1-B8DC-8C474008AD55} {7B803846-91AE-4B98-AC93-D3FCFB2DE5AA} = {6D41796B-9904-40B8-BBCB-40B2D1BAE44B} {335D51AC-1DCF-4487-A2BD-34CE2F17B3C4} = {5ECC38F0-16FD-47E1-B8DC-8C474008AD55} + {E85F3614-79B6-4652-BDB0-64AF68874CE0} = {6D41796B-9904-40B8-BBCB-40B2D1BAE44B} + {D60CFCAD-4A13-4047-91C8-9D7DF4753493} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} + {A04A0416-5E35-4DD0-8226-63D941B28467} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5AE8C9D7-2613-4E1A-A4F2-579BAC28D0A2} diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 9836255cc..f4a49ea79 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -1480,7 +1480,7 @@ private % Make_%() if (event.Name() == "CanExecuteChanged" && event_type == "global::System.EventHandler") { auto parent_type = w.write_temp("%", bind(event.Parent(), typedef_name_type::NonProjected, true)); - if (parent_type == "Microsoft.UI.Xaml.Input.ICommand") + if (parent_type == "Microsoft.UI.Xaml.Input.ICommand" || parent_type == "Windows.UI.Xaml.Input.ICommand") { event_type = "global::System.EventHandler"; } diff --git a/src/cswinrt/cswinrt.vcxproj b/src/cswinrt/cswinrt.vcxproj index 3613dc553..d5cc68b7e 100644 --- a/src/cswinrt/cswinrt.vcxproj +++ b/src/cswinrt/cswinrt.vcxproj @@ -111,6 +111,12 @@ + + + + + + diff --git a/src/cswinrt/cswinrt.vcxproj.filters b/src/cswinrt/cswinrt.vcxproj.filters index 1a891f07e..0f31137c2 100644 --- a/src/cswinrt/cswinrt.vcxproj.filters +++ b/src/cswinrt/cswinrt.vcxproj.filters @@ -51,6 +51,21 @@ {369a6d8a-43e6-48af-82c1-bb2e555909a4} + + {22aeef74-f4df-40f4-a18f-8053ac54f966} + + + {bb545b29-ba72-4949-b044-790f57ba17a5} + + + {8451fa83-9750-4aec-ae8c-a4149c4b98a6} + + + {98453be9-888b-4032-b5cd-4034b17197c9} + + + {03980bb6-f657-4c07-a456-5b4774de5773} + diff --git a/src/cswinrt/helpers.h b/src/cswinrt/helpers.h index fcc3f7cc3..93b1ce916 100644 --- a/src/cswinrt/helpers.h +++ b/src/cswinrt/helpers.h @@ -670,7 +670,8 @@ namespace cswinrt } mapped_types[] = { // Make sure to keep this table consistent with the registrations in WinRT.Runtime/Projections.cs - // and the reverse mapping in WinRT.SourceGenerator/WinRTTypeWriter.cs. + // and the reverse mapping in WinRT.SourceGenerator/TypeMapper.cs. + // This table can include both the MUX and WUX types as only one will be selected at runtime. // NOTE: Must keep namespaces sorted (outer) and abi type names sorted (inner) { "Microsoft.UI.Xaml", { @@ -816,13 +817,92 @@ namespace cswinrt { "IColorHelperStatics2" }, } }, - // Temporary, until WinUI provides TypeName + { "Windows.UI.Xaml", + { + { "CornerRadius", "Windows.UI.Xaml", "CornerRadius" }, + { "CornerRadiusHelper" }, + { "Duration", "Windows.UI.Xaml", "Duration" }, + { "DurationHelper" }, + { "DurationType", "Windows.UI.Xaml", "DurationType" }, + { "GridLength", "Windows.UI.Xaml", "GridLength" }, + { "GridLengthHelper" }, + { "GridUnitType", "Windows.UI.Xaml", "GridUnitType" }, + { "ICornerRadiusHelper" }, + { "ICornerRadiusHelperStatics" }, + { "IDurationHelper" }, + { "IDurationHelperStatics" }, + { "IGridLengthHelper" }, + { "IGridLengthHelperStatics" }, + { "IThicknessHelper" }, + { "IThicknessHelperStatics" }, + { "Thickness", "Windows.UI.Xaml", "Thickness" }, + { "ThicknessHelper" }, + { "IXamlServiceProvider", "System", "IServiceProvider" }, + } + }, + { "Windows.UI.Xaml.Controls.Primitives", + { + { "GeneratorPosition", "Windows.UI.Xaml.Controls.Primitives", "GeneratorPosition" }, + { "GeneratorPositionHelper" }, + { "IGeneratorPositionHelper" }, + { "IGeneratorPositionHelperStatics" }, + } + }, + { "Windows.UI.Xaml.Data", + { + { "DataErrorsChangedEventArgs", "System.ComponentModel", "DataErrorsChangedEventArgs" }, + { "INotifyDataErrorInfo", "System.ComponentModel", "INotifyDataErrorInfo", true, true }, + { "INotifyPropertyChanged", "System.ComponentModel", "INotifyPropertyChanged" }, + { "PropertyChangedEventArgs", "System.ComponentModel", "PropertyChangedEventArgs" }, + { "PropertyChangedEventHandler", "System.ComponentModel", "PropertyChangedEventHandler" }, + } + }, + { "Windows.UI.Xaml.Input", + { + { "ICommand", "System.Windows.Input", "ICommand", true } + } + }, { "Windows.UI.Xaml.Interop", { + { "IBindableIterable", "System.Collections", "IEnumerable", true, true }, + { "IBindableVector", "System.Collections", "IList", true, true }, + { "INotifyCollectionChanged", "System.Collections.Specialized", "INotifyCollectionChanged", true }, + { "NotifyCollectionChangedAction", "System.Collections.Specialized", "NotifyCollectionChangedAction" }, + { "NotifyCollectionChangedEventArgs", "System.Collections.Specialized", "NotifyCollectionChangedEventArgs", true }, + { "NotifyCollectionChangedEventHandler", "System.Collections.Specialized", "NotifyCollectionChangedEventHandler", true }, { "TypeKind", "Windows.UI.Xaml.Interop", "TypeKind", true }, { "TypeName", "System", "Type", true } } }, + { "Windows.UI.Xaml.Media", + { + { "IMatrixHelper" }, + { "IMatrixHelperStatics" }, + { "Matrix", "Windows.UI.Xaml.Media", "Matrix" }, + { "MatrixHelper" }, + } + }, + { "Windows.UI.Xaml.Media.Animation", + { + { "IKeyTimeHelper" }, + { "IKeyTimeHelperStatics" }, + { "IRepeatBehaviorHelper" }, + { "IRepeatBehaviorHelperStatics" }, + { "KeyTime", "Windows.UI.Xaml.Media.Animation", "KeyTime" }, + { "KeyTimeHelper" }, + { "RepeatBehavior", "Windows.UI.Xaml.Media.Animation", "RepeatBehavior" }, + { "RepeatBehaviorHelper" }, + { "RepeatBehaviorType", "Windows.UI.Xaml.Media.Animation", "RepeatBehaviorType" } + } + }, + { "Windows.UI.Xaml.Media.Media3D", + { + { "IMatrix3DHelper" }, + { "IMatrix3DHelperStatics" }, + { "Matrix3D", "Windows.UI.Xaml.Media.Media3D", "Matrix3D" }, + { "Matrix3DHelper" }, + } + }, }; auto nsItr = std::lower_bound(std::begin(mapped_types), std::end(mapped_types), typeNamespace, [](auto&& v, std::string_view ns) diff --git a/src/cswinrt/main.cpp b/src/cswinrt/main.cpp index 8df213ac7..312b695e4 100644 --- a/src/cswinrt/main.cpp +++ b/src/cswinrt/main.cpp @@ -33,6 +33,7 @@ namespace cswinrt { "output", 0, 1, "", "Location of generated projection" }, { "include", 0, option::no_max, "", "One or more prefixes to include in projection" }, { "exclude", 0, option::no_max, "", "One or more prefixes to exclude from projection" }, + { "addition_exclude", 0, option::no_max, "", "One or more namespace prefixes to exclude from the projection additions" }, { "target", 0, 1, "", "Target TFM for projection. Omit for compatibility with .NET 6." }, { "component", 0, 0, {}, "Generate component projection." }, { "verbose", 0, 0, {}, "Show detailed progress information" }, @@ -113,6 +114,11 @@ Where is one or more of: settings.exclude.insert(exclude); } + for (auto&& addition_exclude : args.values("addition_exclude")) + { + settings.addition_exclude.insert(addition_exclude); + } + settings.output_folder = std::filesystem::absolute(args.value("output", "output")); create_directories(settings.output_folder); } @@ -137,6 +143,9 @@ Where is one or more of: cache c{ get_files_to_cache() }; settings.filter = { settings.include, settings.exclude }; + // Include all additions for included namespaces by default + settings.addition_filter = { settings.include, settings.addition_exclude }; + std::set componentActivatableClasses; if (settings.component) { @@ -322,7 +331,7 @@ Where is one or more of: // Custom additions to namespaces for (auto addition : strings::additions) { - if (ns == addition.name) + if (ns == addition.name && settings.addition_filter.includes(ns)) { w.write(addition.value); } diff --git a/src/cswinrt/settings.h b/src/cswinrt/settings.h index efdb304eb..b095f5d33 100644 --- a/src/cswinrt/settings.h +++ b/src/cswinrt/settings.h @@ -9,7 +9,9 @@ namespace cswinrt bool verbose{}; std::set include; std::set exclude; + std::set addition_exclude; winmd::reader::filter filter; + winmd::reader::filter addition_filter; bool netstandard_compat{}; bool net7_0_or_greater{}; bool component{}; diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml.Controls/Windows.UI.Xaml.Controls.Primitives.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml.Controls/Windows.UI.Xaml.Controls.Primitives.cs new file mode 100644 index 000000000..ec28e9295 --- /dev/null +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml.Controls/Windows.UI.Xaml.Controls.Primitives.cs @@ -0,0 +1,73 @@ + +namespace Windows.UI.Xaml.Controls.Primitives +{ + using global::Windows.Foundation; + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Controls.Primitives.GeneratorPosition))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct GeneratorPosition + { + private int _index; + private int _offset; + + public int Index { get { return _index; } set { _index = value; } } + public int Offset { get { return _offset; } set { _offset = value; } } + + public GeneratorPosition(int index, int offset) + { + _index = index; + _offset = offset; + } + + public override int GetHashCode() + { + return _index.GetHashCode() + _offset.GetHashCode(); + } + + public override string ToString() + { + return string.Concat("GeneratorPosition (", _index.ToString(global::System.Globalization.CultureInfo.InvariantCulture), ",", _offset.ToString(global::System.Globalization.CultureInfo.InvariantCulture), ")"); + } + + public override bool Equals(object o) + { + if (o is GeneratorPosition) + { + GeneratorPosition that = (GeneratorPosition)o; + return _index == that._index && + _offset == that._offset; + } + return false; + } + + public static bool operator ==(GeneratorPosition gp1, GeneratorPosition gp2) + { + return gp1._index == gp2._index && + gp1._offset == gp2._offset; + } + + public static bool operator !=(GeneratorPosition gp1, GeneratorPosition gp2) + { + return !(gp1 == gp2); + } + } +} + +namespace ABI.Windows.UI.Xaml.Controls.Primitives +{ +#if EMBED + internal +#else + public +#endif + static class GeneratorPosition + { + public static string GetGuidSignature() => $"struct(Windows.UI.Xaml.Controls.Primitives.GeneratorPosition;i4;i4)"; + } +} diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.cs new file mode 100644 index 000000000..259898959 --- /dev/null +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.cs @@ -0,0 +1,326 @@ + +namespace Windows.UI.Xaml.Media.Animation +{ + using global::Windows.Foundation; + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Animation.KeyTime))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct KeyTime + { + private TimeSpan _timeSpan; + + public static KeyTime FromTimeSpan(TimeSpan timeSpan) + { + if (timeSpan < TimeSpan.Zero) + { + throw new ArgumentOutOfRangeException(nameof(timeSpan)); + } + + KeyTime keyTime = default; + + keyTime._timeSpan = timeSpan; + + return keyTime; + } + + public static bool Equals(KeyTime keyTime1, KeyTime keyTime2) + { + return (keyTime1._timeSpan == keyTime2._timeSpan); + } + + public static bool operator ==(KeyTime keyTime1, KeyTime keyTime2) + { + return KeyTime.Equals(keyTime1, keyTime2); + } + + public static bool operator !=(KeyTime keyTime1, KeyTime keyTime2) + { + return !KeyTime.Equals(keyTime1, keyTime2); + } + + public bool Equals(KeyTime value) + { + return KeyTime.Equals(this, value); + } + + public override bool Equals(object value) + { + return value is KeyTime && this == (KeyTime)value; + } + + public override int GetHashCode() + { + return _timeSpan.GetHashCode(); + } + + public override string ToString() + { + return _timeSpan.ToString(); + } + + public static implicit operator KeyTime(TimeSpan timeSpan) + { + return KeyTime.FromTimeSpan(timeSpan); + } + + public TimeSpan TimeSpan + { + get + { + return _timeSpan; + } + } + } + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] +#if EMBED + internal +#else + public +#endif + enum RepeatBehaviorType + { + Count, + Duration, + Forever + } + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Animation.RepeatBehavior))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct RepeatBehavior : IFormattable + { + private double _Count; + private TimeSpan _Duration; + private RepeatBehaviorType _Type; + + internal static bool IsFinite(double value) + { + return !(double.IsNaN(value) || double.IsInfinity(value)); + } + + public RepeatBehavior(double count) + { + if (!IsFinite(count) || count < 0.0) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + + _Duration = new TimeSpan(0); + _Count = count; + _Type = RepeatBehaviorType.Count; + } + + public RepeatBehavior(TimeSpan duration) + { + if (duration < new TimeSpan(0)) + { + throw new ArgumentOutOfRangeException(nameof(duration)); + } + + _Duration = duration; + _Count = 0.0; + _Type = RepeatBehaviorType.Duration; + } + + public static RepeatBehavior Forever + { + get + { + RepeatBehavior forever = default; + forever.Type = RepeatBehaviorType.Forever; + + return forever; + } + } + + public bool HasCount + { + get + { + return Type == RepeatBehaviorType.Count; + } + } + + public bool HasDuration + { + get + { + return Type == RepeatBehaviorType.Duration; + } + } + + public double Count + { + get { return _Count; } + set { _Count = value; } + } + + public TimeSpan Duration + { + get { return _Duration; } + set { _Duration = value; } + } + + public RepeatBehaviorType Type + { + get { return _Type; } + set { _Type = value; } + } + + public override string ToString() + { + return InternalToString(null, null); + } + + public string ToString(IFormatProvider formatProvider) + { + return InternalToString(null, formatProvider); + } + + string IFormattable.ToString(string format, IFormatProvider formatProvider) + { + return InternalToString(format, formatProvider); + } + + internal string InternalToString(string format, IFormatProvider formatProvider) + { + switch (_Type) + { + case RepeatBehaviorType.Forever: + + return "Forever"; + + case RepeatBehaviorType.Count: + + global::System.Text.StringBuilder sb = new global::System.Text.StringBuilder(); + + sb.AppendFormat( + formatProvider, + "{0:" + format + "}x", + _Count); + + return sb.ToString(); + + case RepeatBehaviorType.Duration: + + return _Duration.ToString(); + + default: + return string.Empty; + } + } + + public override bool Equals(object value) + { + if (value is RepeatBehavior) + { + return this.Equals((RepeatBehavior)value); + } + else + { + return false; + } + } + + public bool Equals(RepeatBehavior repeatBehavior) + { + if (_Type == repeatBehavior._Type) + { + return _Type switch + { + RepeatBehaviorType.Forever => true, + RepeatBehaviorType.Count => _Count == repeatBehavior._Count, + RepeatBehaviorType.Duration => _Duration == repeatBehavior._Duration, + _ => false, + }; + } + else + { + return false; + } + } + + public static bool Equals(RepeatBehavior repeatBehavior1, RepeatBehavior repeatBehavior2) + { + return repeatBehavior1.Equals(repeatBehavior2); + } + + public override int GetHashCode() + { + return _Type switch + { + RepeatBehaviorType.Count => _Count.GetHashCode(), + RepeatBehaviorType.Duration => _Duration.GetHashCode(), + + // We try to choose an unlikely hash code value for Forever. + // All Forevers need to return the same hash code value. + RepeatBehaviorType.Forever => int.MaxValue - 42, + + _ => base.GetHashCode(), + }; + } + + public static bool operator ==(RepeatBehavior repeatBehavior1, RepeatBehavior repeatBehavior2) + { + return repeatBehavior1.Equals(repeatBehavior2); + } + + public static bool operator !=(RepeatBehavior repeatBehavior1, RepeatBehavior repeatBehavior2) + { + return !repeatBehavior1.Equals(repeatBehavior2); + } + } +} + +namespace ABI.Windows.UI.Xaml.Media.Animation +{ +#if EMBED + internal +#else + public +#endif + static class KeyTime + { + public static string GetGuidSignature() + { + string timeSpanSignature = global::WinRT.GuidGenerator.GetSignature(typeof(global::System.TimeSpan)); + return $"struct(Windows.UI.Xaml.Media.Animation.KeyTime;{timeSpanSignature})"; + } + } + +#if EMBED + internal +#else + public +#endif + static class RepeatBehavior + { + public static string GetGuidSignature() + { + string timeSpanSignature = global::WinRT.GuidGenerator.GetSignature(typeof(global::System.TimeSpan)); + return $"struct(Windows.UI.Xaml.Media.Animation.RepeatBehavior;f8;{timeSpanSignature};{RepeatBehaviorType.GetGuidSignature()})"; + } + } + +#if EMBED + internal +#else + public +#endif + static class RepeatBehaviorType + { + public static string GetGuidSignature() => "enum(Windows.UI.Xaml.Media.Animation.RepeatBehaviorType;i4)"; + } +} diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.cs new file mode 100644 index 000000000..98dfb069e --- /dev/null +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.cs @@ -0,0 +1,711 @@ + +namespace Windows.UI.Xaml.Media.Media3D +{ + using global::Windows.Foundation; + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Media3D.Matrix3D))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct Matrix3D : IFormattable + { + // Assuming this matrix has fourth column of 0,0,0,1 and isn't identity this function: + // Returns false if HasInverse is false, otherwise inverts the matrix. + private bool NormalizedAffineInvert() + { + double z20 = _m12 * _m23 - _m22 * _m13; + double z10 = _m32 * _m13 - _m12 * _m33; + double z00 = _m22 * _m33 - _m32 * _m23; + double det = _m31 * z20 + _m21 * z10 + _m11 * z00; + + if (IsZero(det)) + { + return false; + } + + // Compute 3x3 non-zero cofactors for the 2nd column + double z21 = _m21 * _m13 - _m11 * _m23; + double z11 = _m11 * _m33 - _m31 * _m13; + double z01 = _m31 * _m23 - _m21 * _m33; + + // Compute all six 2x2 determinants of 1st two columns + double y01 = _m11 * _m22 - _m21 * _m12; + double y02 = _m11 * _m32 - _m31 * _m12; + double y03 = _m11 * _offsetY - _offsetX * _m12; + double y12 = _m21 * _m32 - _m31 * _m22; + double y13 = _m21 * _offsetY - _offsetX * _m22; + double y23 = _m31 * _offsetY - _offsetX * _m32; + + // Compute all non-zero and non-one 3x3 cofactors for 2nd + // two columns + double z23 = _m23 * y03 - _offsetZ * y01 - _m13 * y13; + double z13 = _m13 * y23 - _m33 * y03 + _offsetZ * y02; + double z03 = _m33 * y13 - _offsetZ * y12 - _m23 * y23; + double z22 = y01; + double z12 = -y02; + double z02 = y12; + + double rcp = 1.0 / det; + + // Multiply all 3x3 cofactors by reciprocal & transpose + _m11 = (z00 * rcp); + _m12 = (z10 * rcp); + _m13 = (z20 * rcp); + + _m21 = (z01 * rcp); + _m22 = (z11 * rcp); + _m23 = (z21 * rcp); + + _m31 = (z02 * rcp); + _m32 = (z12 * rcp); + _m33 = (z22 * rcp); + + _offsetX = (z03 * rcp); + _offsetY = (z13 * rcp); + _offsetZ = (z23 * rcp); + + return true; + } + + // RETURNS true if has inverse & invert was done. Otherwise returns false & leaves matrix unchanged. + private bool InvertCore() + { + if (IsAffine) + { + return NormalizedAffineInvert(); + } + + // compute all six 2x2 determinants of 2nd two columns + double y01 = _m13 * _m24 - _m23 * _m14; + double y02 = _m13 * _m34 - _m33 * _m14; + double y03 = _m13 * _m44 - _offsetZ * _m14; + double y12 = _m23 * _m34 - _m33 * _m24; + double y13 = _m23 * _m44 - _offsetZ * _m24; + double y23 = _m33 * _m44 - _offsetZ * _m34; + + // Compute 3x3 cofactors for 1st the column + double z30 = _m22 * y02 - _m32 * y01 - _m12 * y12; + double z20 = _m12 * y13 - _m22 * y03 + _offsetY * y01; + double z10 = _m32 * y03 - _offsetY * y02 - _m12 * y23; + double z00 = _m22 * y23 - _m32 * y13 + _offsetY * y12; + + // Compute 4x4 determinant + double det = _offsetX * z30 + _m31 * z20 + _m21 * z10 + _m11 * z00; + + if (IsZero(det)) + { + return false; + } + + // Compute 3x3 cofactors for the 2nd column + double z31 = _m11 * y12 - _m21 * y02 + _m31 * y01; + double z21 = _m21 * y03 - _offsetX * y01 - _m11 * y13; + double z11 = _m11 * y23 - _m31 * y03 + _offsetX * y02; + double z01 = _m31 * y13 - _offsetX * y12 - _m21 * y23; + + // Compute all six 2x2 determinants of 1st two columns + y01 = _m11 * _m22 - _m21 * _m12; + y02 = _m11 * _m32 - _m31 * _m12; + y03 = _m11 * _offsetY - _offsetX * _m12; + y12 = _m21 * _m32 - _m31 * _m22; + y13 = _m21 * _offsetY - _offsetX * _m22; + y23 = _m31 * _offsetY - _offsetX * _m32; + + // Compute all 3x3 cofactors for 2nd two columns + double z33 = _m13 * y12 - _m23 * y02 + _m33 * y01; + double z23 = _m23 * y03 - _offsetZ * y01 - _m13 * y13; + double z13 = _m13 * y23 - _m33 * y03 + _offsetZ * y02; + double z03 = _m33 * y13 - _offsetZ * y12 - _m23 * y23; + double z32 = _m24 * y02 - _m34 * y01 - _m14 * y12; + double z22 = _m14 * y13 - _m24 * y03 + _m44 * y01; + double z12 = _m34 * y03 - _m44 * y02 - _m14 * y23; + double z02 = _m24 * y23 - _m34 * y13 + _m44 * y12; + + double rcp = 1.0 / det; + + // Multiply all 3x3 cofactors by reciprocal & transpose + _m11 = (z00 * rcp); + _m12 = (z10 * rcp); + _m13 = (z20 * rcp); + _m14 = (z30 * rcp); + + _m21 = (z01 * rcp); + _m22 = (z11 * rcp); + _m23 = (z21 * rcp); + _m24 = (z31 * rcp); + + _m31 = (z02 * rcp); + _m32 = (z12 * rcp); + _m33 = (z22 * rcp); + _m34 = (z32 * rcp); + + _offsetX = (z03 * rcp); + _offsetY = (z13 * rcp); + _offsetZ = (z23 * rcp); + _m44 = (z33 * rcp); + + return true; + } + + public Matrix3D(double m11, double m12, double m13, double m14, + double m21, double m22, double m23, double m24, + double m31, double m32, double m33, double m34, + double offsetX, double offsetY, double offsetZ, double m44) + { + _m11 = m11; + _m12 = m12; + _m13 = m13; + _m14 = m14; + _m21 = m21; + _m22 = m22; + _m23 = m23; + _m24 = m24; + _m31 = m31; + _m32 = m32; + _m33 = m33; + _m34 = m34; + _offsetX = offsetX; + _offsetY = offsetY; + _offsetZ = offsetZ; + _m44 = m44; + } + + // the transform is identity by default + // Actually fill in the fields - some (internal) code uses the fields directly for perf. + private static Matrix3D s_identity = CreateIdentity(); + + public double M11 + { + get + { + return _m11; + } + set + { + _m11 = value; + } + } + + public double M12 + { + get + { + return _m12; + } + set + { + _m12 = value; + } + } + + public double M13 + { + get + { + return _m13; + } + set + { + _m13 = value; + } + } + + public double M14 + { + get + { + return _m14; + } + set + { + _m14 = value; + } + } + + public double M21 + { + get + { + return _m21; + } + set + { + _m21 = value; + } + } + + public double M22 + { + get + { + return _m22; + } + set + { + _m22 = value; + } + } + + public double M23 + { + get + { + return _m23; + } + set + { + _m23 = value; + } + } + + public double M24 + { + get + { + return _m24; + } + set + { + _m24 = value; + } + } + + public double M31 + { + get + { + return _m31; + } + set + { + _m31 = value; + } + } + + public double M32 + { + get + { + return _m32; + } + set + { + _m32 = value; + } + } + + public double M33 + { + get + { + return _m33; + } + set + { + _m33 = value; + } + } + + public double M34 + { + get + { + return _m34; + } + set + { + _m34 = value; + } + } + + public double OffsetX + { + get + { + return _offsetX; + } + set + { + _offsetX = value; + } + } + + public double OffsetY + { + get + { + return _offsetY; + } + set + { + _offsetY = value; + } + } + + public double OffsetZ + { + get + { + return _offsetZ; + } + set + { + _offsetZ = value; + } + } + + public double M44 + { + get + { + return _m44; + } + set + { + _m44 = value; + } + } + + public static Matrix3D Identity + { + get + { + return s_identity; + } + } + + public bool IsIdentity + { + get + { + return (_m11 == 1 && _m12 == 0 && _m13 == 0 && _m14 == 0 && + _m21 == 0 && _m22 == 1 && _m23 == 0 && _m24 == 0 && + _m31 == 0 && _m32 == 0 && _m33 == 1 && _m34 == 0 && + _offsetX == 0 && _offsetY == 0 && _offsetZ == 0 && _m44 == 1); + } + } + + public override string ToString() + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(null /* format string */, null /* format provider */); + } + + public string ToString(IFormatProvider provider) + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(null /* format string */, provider); + } + + string IFormattable.ToString(string format, IFormatProvider provider) + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(format, provider); + } + + private string ConvertToString(string format, IFormatProvider provider) + { + if (IsIdentity) + { + return "Identity"; + } + + // Helper to get the numeric list separator for a given culture. + char separator = TokenizerHelper.GetNumericListSeparator(provider); + return string.Format(provider, + "{1:" + format + "}{0}{2:" + format + "}{0}{3:" + format + "}{0}{4:" + format + "}{0}{5:" + format + + "}{0}{6:" + format + "}{0}{7:" + format + "}{0}{8:" + format + "}{0}{9:" + format + "}{0}{10:" + format + + "}{0}{11:" + format + "}{0}{12:" + format + "}{0}{13:" + format + "}{0}{14:" + format + "}{0}{15:" + format + "}{0}{16:" + format + "}", + separator, + _m11, _m12, _m13, _m14, + _m21, _m22, _m23, _m24, + _m31, _m32, _m33, _m34, + _offsetX, _offsetY, _offsetZ, _m44); + } + + public override int GetHashCode() + { + // Perform field-by-field XOR of HashCodes + return M11.GetHashCode() ^ + M12.GetHashCode() ^ + M13.GetHashCode() ^ + M14.GetHashCode() ^ + M21.GetHashCode() ^ + M22.GetHashCode() ^ + M23.GetHashCode() ^ + M24.GetHashCode() ^ + M31.GetHashCode() ^ + M32.GetHashCode() ^ + M33.GetHashCode() ^ + M34.GetHashCode() ^ + OffsetX.GetHashCode() ^ + OffsetY.GetHashCode() ^ + OffsetZ.GetHashCode() ^ + M44.GetHashCode(); + } + + public override bool Equals(object o) + { + return o is Matrix3D && Matrix3D.Equals(this, (Matrix3D)o); + } + + public bool Equals(Matrix3D value) + { + return Matrix3D.Equals(this, value); + } + + public static bool operator ==(Matrix3D matrix1, Matrix3D matrix2) + { + return matrix1.M11 == matrix2.M11 && + matrix1.M12 == matrix2.M12 && + matrix1.M13 == matrix2.M13 && + matrix1.M14 == matrix2.M14 && + matrix1.M21 == matrix2.M21 && + matrix1.M22 == matrix2.M22 && + matrix1.M23 == matrix2.M23 && + matrix1.M24 == matrix2.M24 && + matrix1.M31 == matrix2.M31 && + matrix1.M32 == matrix2.M32 && + matrix1.M33 == matrix2.M33 && + matrix1.M34 == matrix2.M34 && + matrix1.OffsetX == matrix2.OffsetX && + matrix1.OffsetY == matrix2.OffsetY && + matrix1.OffsetZ == matrix2.OffsetZ && + matrix1.M44 == matrix2.M44; + } + + public static bool operator !=(Matrix3D matrix1, Matrix3D matrix2) + { + return !(matrix1 == matrix2); + } + + public static Matrix3D operator *(Matrix3D matrix1, Matrix3D matrix2) + { + Matrix3D matrix3D = default; + + matrix3D.M11 = matrix1.M11 * matrix2.M11 + + matrix1.M12 * matrix2.M21 + + matrix1.M13 * matrix2.M31 + + matrix1.M14 * matrix2.OffsetX; + matrix3D.M12 = matrix1.M11 * matrix2.M12 + + matrix1.M12 * matrix2.M22 + + matrix1.M13 * matrix2.M32 + + matrix1.M14 * matrix2.OffsetY; + matrix3D.M13 = matrix1.M11 * matrix2.M13 + + matrix1.M12 * matrix2.M23 + + matrix1.M13 * matrix2.M33 + + matrix1.M14 * matrix2.OffsetZ; + matrix3D.M14 = matrix1.M11 * matrix2.M14 + + matrix1.M12 * matrix2.M24 + + matrix1.M13 * matrix2.M34 + + matrix1.M14 * matrix2.M44; + matrix3D.M21 = matrix1.M21 * matrix2.M11 + + matrix1.M22 * matrix2.M21 + + matrix1.M23 * matrix2.M31 + + matrix1.M24 * matrix2.OffsetX; + matrix3D.M22 = matrix1.M21 * matrix2.M12 + + matrix1.M22 * matrix2.M22 + + matrix1.M23 * matrix2.M32 + + matrix1.M24 * matrix2.OffsetY; + matrix3D.M23 = matrix1.M21 * matrix2.M13 + + matrix1.M22 * matrix2.M23 + + matrix1.M23 * matrix2.M33 + + matrix1.M24 * matrix2.OffsetZ; + matrix3D.M24 = matrix1.M21 * matrix2.M14 + + matrix1.M22 * matrix2.M24 + + matrix1.M23 * matrix2.M34 + + matrix1.M24 * matrix2.M44; + matrix3D.M31 = matrix1.M31 * matrix2.M11 + + matrix1.M32 * matrix2.M21 + + matrix1.M33 * matrix2.M31 + + matrix1.M34 * matrix2.OffsetX; + matrix3D.M32 = matrix1.M31 * matrix2.M12 + + matrix1.M32 * matrix2.M22 + + matrix1.M33 * matrix2.M32 + + matrix1.M34 * matrix2.OffsetY; + matrix3D.M33 = matrix1.M31 * matrix2.M13 + + matrix1.M32 * matrix2.M23 + + matrix1.M33 * matrix2.M33 + + matrix1.M34 * matrix2.OffsetZ; + matrix3D.M34 = matrix1.M31 * matrix2.M14 + + matrix1.M32 * matrix2.M24 + + matrix1.M33 * matrix2.M34 + + matrix1.M34 * matrix2.M44; + matrix3D.OffsetX = matrix1.OffsetX * matrix2.M11 + + matrix1.OffsetY * matrix2.M21 + + matrix1.OffsetZ * matrix2.M31 + + matrix1.M44 * matrix2.OffsetX; + matrix3D.OffsetY = matrix1.OffsetX * matrix2.M12 + + matrix1.OffsetY * matrix2.M22 + + matrix1.OffsetZ * matrix2.M32 + + matrix1.M44 * matrix2.OffsetY; + matrix3D.OffsetZ = matrix1.OffsetX * matrix2.M13 + + matrix1.OffsetY * matrix2.M23 + + matrix1.OffsetZ * matrix2.M33 + + matrix1.M44 * matrix2.OffsetZ; + matrix3D.M44 = matrix1.OffsetX * matrix2.M14 + + matrix1.OffsetY * matrix2.M24 + + matrix1.OffsetZ * matrix2.M34 + + matrix1.M44 * matrix2.M44; + + // matrix3D._type is not set. + + return matrix3D; + } + + public bool HasInverse + { + get + { + return !IsZero(Determinant); + } + } + + public void Invert() + { + if (!InvertCore()) + { + throw new InvalidOperationException(); + } + } + + private static Matrix3D CreateIdentity() + { + Matrix3D matrix3D = default; + matrix3D.SetMatrix(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + return matrix3D; + } + + private void SetMatrix(double m11, double m12, double m13, double m14, + double m21, double m22, double m23, double m24, + double m31, double m32, double m33, double m34, + double offsetX, double offsetY, double offsetZ, double m44) + { + _m11 = m11; + _m12 = m12; + _m13 = m13; + _m14 = m14; + _m21 = m21; + _m22 = m22; + _m23 = m23; + _m24 = m24; + _m31 = m31; + _m32 = m32; + _m33 = m33; + _m34 = m34; + _offsetX = offsetX; + _offsetY = offsetY; + _offsetZ = offsetZ; + _m44 = m44; + } + + private static bool Equals(Matrix3D matrix1, Matrix3D matrix2) + { + return matrix1.M11.Equals(matrix2.M11) && + matrix1.M12.Equals(matrix2.M12) && + matrix1.M13.Equals(matrix2.M13) && + matrix1.M14.Equals(matrix2.M14) && + matrix1.M21.Equals(matrix2.M21) && + matrix1.M22.Equals(matrix2.M22) && + matrix1.M23.Equals(matrix2.M23) && + matrix1.M24.Equals(matrix2.M24) && + matrix1.M31.Equals(matrix2.M31) && + matrix1.M32.Equals(matrix2.M32) && + matrix1.M33.Equals(matrix2.M33) && + matrix1.M34.Equals(matrix2.M34) && + matrix1.OffsetX.Equals(matrix2.OffsetX) && + matrix1.OffsetY.Equals(matrix2.OffsetY) && + matrix1.OffsetZ.Equals(matrix2.OffsetZ) && + matrix1.M44.Equals(matrix2.M44); + } + + private double GetNormalizedAffineDeterminant() + { + double z20 = _m12 * _m23 - _m22 * _m13; + double z10 = _m32 * _m13 - _m12 * _m33; + double z00 = _m22 * _m33 - _m32 * _m23; + + return _m31 * z20 + _m21 * z10 + _m11 * z00; + } + + private bool IsAffine + { + get + { + return (_m14 == 0.0 && _m24 == 0.0 && _m34 == 0.0 && _m44 == 1.0); + } + } + + private double Determinant + { + get + { + if (IsAffine) + { + return GetNormalizedAffineDeterminant(); + } + + // compute all six 2x2 determinants of 2nd two columns + double y01 = _m13 * _m24 - _m23 * _m14; + double y02 = _m13 * _m34 - _m33 * _m14; + double y03 = _m13 * _m44 - _offsetZ * _m14; + double y12 = _m23 * _m34 - _m33 * _m24; + double y13 = _m23 * _m44 - _offsetZ * _m24; + double y23 = _m33 * _m44 - _offsetZ * _m34; + + // Compute 3x3 cofactors for 1st the column + double z30 = _m22 * y02 - _m32 * y01 - _m12 * y12; + double z20 = _m12 * y13 - _m22 * y03 + _offsetY * y01; + double z10 = _m32 * y03 - _offsetY * y02 - _m12 * y23; + double z00 = _m22 * y23 - _m32 * y13 + _offsetY * y12; + + return _offsetX * z30 + _m31 * z20 + _m21 * z10 + _m11 * z00; + } + } + + private static bool IsZero(double value) + { + return Math.Abs(value) < 10.0 * DBL_EPSILON_RELATIVE_1; + } + + private const double DBL_EPSILON_RELATIVE_1 = 1.1102230246251567e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */ + + private double _m11; + private double _m12; + private double _m13; + private double _m14; + private double _m21; + private double _m22; + private double _m23; + private double _m24; + private double _m31; + private double _m32; + private double _m33; + private double _m34; + private double _offsetX; + private double _offsetY; + private double _offsetZ; + private double _m44; + } +} + +namespace ABI.Windows.UI.Xaml.Media.Media3D +{ +#if EMBED + internal +#else + public +#endif + static class Matrix3D + { + public static string GetGuidSignature() => + $"struct(Windows.UI.Xaml.Media.Media3D.Matrix3D;f8;f8;f8;f8;f8;f8;f8;f8;f8;f8;f8;f8;f8;f8;f8;f8)"; + } +} diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.cs new file mode 100644 index 000000000..b156e5104 --- /dev/null +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.cs @@ -0,0 +1,263 @@ + +namespace Windows.UI.Xaml.Media +{ + using global::Windows.Foundation; + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Matrix))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct Matrix : IFormattable + { + public Matrix(double m11, double m12, + double m21, double m22, + double offsetX, double offsetY) + { + _m11 = m11; + _m12 = m12; + _m21 = m21; + _m22 = m22; + _offsetX = offsetX; + _offsetY = offsetY; + } + + // the transform is identity by default + private static Matrix s_identity = CreateIdentity(); + + public double M11 + { + get + { + return _m11; + } + set + { + _m11 = value; + } + } + + public double M12 + { + get + { + return _m12; + } + set + { + _m12 = value; + } + } + + public double M21 + { + get + { + return _m21; + } + set + { + _m21 = value; + } + } + + public double M22 + { + get + { + return _m22; + } + set + { + _m22 = value; + } + } + + public double OffsetX + { + get + { + return _offsetX; + } + set + { + _offsetX = value; + } + } + + public double OffsetY + { + get + { + return _offsetY; + } + set + { + _offsetY = value; + } + } + + public static Matrix Identity + { + get + { + return s_identity; + } + } + + public bool IsIdentity + { + get + { + return (_m11 == 1 && _m12 == 0 && _m21 == 0 && _m22 == 1 && _offsetX == 0 && _offsetY == 0); + } + } + + public override string ToString() + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(null /* format string */, null /* format provider */); + } + + public string ToString(IFormatProvider provider) + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(null /* format string */, provider); + } + + string IFormattable.ToString(string format, IFormatProvider provider) + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(format, provider); + } + + private string ConvertToString(string format, IFormatProvider provider) + { + if (IsIdentity) + { + return "Identity"; + } + + // Helper to get the numeric list separator for a given culture. + char separator = TokenizerHelper.GetNumericListSeparator(provider); + return string.Format(provider, + "{1:" + format + "}{0}{2:" + format + "}{0}{3:" + format + "}{0}{4:" + format + "}{0}{5:" + format + "}{0}{6:" + format + "}", + separator, + _m11, + _m12, + _m21, + _m22, + _offsetX, + _offsetY); + } + + public Point Transform(Point point) + { + float x = (float)point.X; + float y = (float)point.Y; + this.MultiplyPoint(ref x, ref y); + Point point2 = new Point(x, y); + return point2; + } + + public override int GetHashCode() + { + // Perform field-by-field XOR of HashCodes + return M11.GetHashCode() ^ + M12.GetHashCode() ^ + M21.GetHashCode() ^ + M22.GetHashCode() ^ + OffsetX.GetHashCode() ^ + OffsetY.GetHashCode(); + } + + public override bool Equals(object o) + { + return o is Matrix && Matrix.Equals(this, (Matrix)o); + } + + public bool Equals(Matrix value) + { + return Matrix.Equals(this, value); + } + + public static bool operator ==(Matrix matrix1, Matrix matrix2) + { + return matrix1.M11 == matrix2.M11 && + matrix1.M12 == matrix2.M12 && + matrix1.M21 == matrix2.M21 && + matrix1.M22 == matrix2.M22 && + matrix1.OffsetX == matrix2.OffsetX && + matrix1.OffsetY == matrix2.OffsetY; + } + + public static bool operator !=(Matrix matrix1, Matrix matrix2) + { + return !(matrix1 == matrix2); + } + + private static Matrix CreateIdentity() + { + Matrix matrix = default; + matrix.SetMatrix(1, 0, + 0, 1, + 0, 0); + return matrix; + } + + private void SetMatrix(double m11, double m12, + double m21, double m22, + double offsetX, double offsetY) + { + _m11 = m11; + _m12 = m12; + _m21 = m21; + _m22 = m22; + _offsetX = offsetX; + _offsetY = offsetY; + } + + private void MultiplyPoint(ref float x, ref float y) + { + double num = (y * _m21) + _offsetX; + double num2 = (x * _m12) + _offsetY; + x *= (float)_m11; + x += (float)num; + y *= (float)_m22; + y += (float)num2; + } + + private static bool Equals(Matrix matrix1, Matrix matrix2) + { + return matrix1.M11.Equals(matrix2.M11) && + matrix1.M12.Equals(matrix2.M12) && + matrix1.M21.Equals(matrix2.M21) && + matrix1.M22.Equals(matrix2.M22) && + matrix1.OffsetX.Equals(matrix2.OffsetX) && + matrix1.OffsetY.Equals(matrix2.OffsetY); + } + + private double _m11; + private double _m12; + private double _m21; + private double _m22; + private double _offsetX; + private double _offsetY; + } +} + +namespace ABI.Windows.UI.Xaml.Media +{ +#if EMBED + internal +#else + public +#endif + static class Matrix + { + public static string GetGuidSignature() => $"struct(Windows.UI.Xaml.Media.Matrix;f8;f8;f8;f8;f8;f8)"; + } +} diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.SR.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.SR.cs new file mode 100644 index 000000000..cbb4596bb --- /dev/null +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.SR.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Windows.UI.Xaml +{ + static class SR + { + public static string DirectUI_CornerRadius_InvalidMember = "Invalid value for {0} property on CornerRadius."; + public static string DirectUI_InvalidArgument = "Invalid argument."; + public static string ElementNotAvailable_Default = "The element is not available."; + public static string ElementNotEnabled_Default = "The element is not enabled."; + public static string XamlParse_Default = "XAML parsing failed."; + public static string LayoutCycle_Default = "A cycle occurred while laying out the GUI."; + public static string PlatformNotSupported_WindowsRuntime = "Windows Runtime (WinRT) is not supported on this platform."; + } +} diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.cs new file mode 100644 index 000000000..341d016d6 --- /dev/null +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.cs @@ -0,0 +1,774 @@ + +namespace Windows.UI.Xaml +{ + using global::Windows.Foundation; + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.CornerRadius))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct CornerRadius + { + private double _TopLeft; + private double _TopRight; + private double _BottomRight; + private double _BottomLeft; + + public CornerRadius(double uniformRadius) + { + Validate(uniformRadius, uniformRadius, uniformRadius, uniformRadius); + _TopLeft = _TopRight = _BottomRight = _BottomLeft = uniformRadius; + } + + public CornerRadius(double topLeft, double topRight, double bottomRight, double bottomLeft) + { + Validate(topLeft, topRight, bottomRight, bottomLeft); + + _TopLeft = topLeft; + _TopRight = topRight; + _BottomRight = bottomRight; + _BottomLeft = bottomLeft; + } + + private static void Validate(double topLeft, double topRight, double bottomRight, double bottomLeft) + { + if (topLeft < 0.0 || double.IsNaN(topLeft)) + throw new ArgumentException(string.Format(SR.DirectUI_CornerRadius_InvalidMember, "TopLeft")); + + if (topRight < 0.0 || double.IsNaN(topRight)) + throw new ArgumentException(string.Format(SR.DirectUI_CornerRadius_InvalidMember, "TopRight")); + + if (bottomRight < 0.0 || double.IsNaN(bottomRight)) + throw new ArgumentException(string.Format(SR.DirectUI_CornerRadius_InvalidMember, "BottomRight")); + + if (bottomLeft < 0.0 || double.IsNaN(bottomLeft)) + throw new ArgumentException(string.Format(SR.DirectUI_CornerRadius_InvalidMember, "BottomLeft")); + } + + public override string ToString() + { + return ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + + internal string ToString(global::System.Globalization.CultureInfo cultureInfo) + { + char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo); + + // Initial capacity [64] is an estimate based on a sum of: + // 48 = 4x double (twelve digits is generous for the range of values likely) + // 8 = 4x Unit Type string (approx two characters) + // 4 = 4x separator characters + global::System.Text.StringBuilder sb = new global::System.Text.StringBuilder(64); + + sb.Append(InternalToString(_TopLeft, cultureInfo)); + sb.Append(listSeparator); + sb.Append(InternalToString(_TopRight, cultureInfo)); + sb.Append(listSeparator); + sb.Append(InternalToString(_BottomRight, cultureInfo)); + sb.Append(listSeparator); + sb.Append(InternalToString(_BottomLeft, cultureInfo)); + return sb.ToString(); + } + + internal string InternalToString(double l, global::System.Globalization.CultureInfo cultureInfo) + { + if (double.IsNaN(l)) return "Auto"; + return Convert.ToString(l, cultureInfo); + } + + public override bool Equals(object obj) + { + if (obj is CornerRadius) + { + CornerRadius otherObj = (CornerRadius)obj; + return (this == otherObj); + } + return (false); + } + + public bool Equals(CornerRadius cornerRadius) + { + return (this == cornerRadius); + } + + public override int GetHashCode() + { + return _TopLeft.GetHashCode() ^ _TopRight.GetHashCode() ^ _BottomLeft.GetHashCode() ^ _BottomRight.GetHashCode(); + } + + public static bool operator ==(CornerRadius cr1, CornerRadius cr2) + { + return cr1._TopLeft == cr2._TopLeft && cr1._TopRight == cr2._TopRight && cr1._BottomRight == cr2._BottomRight && cr1._BottomLeft == cr2._BottomLeft; + } + + public static bool operator !=(CornerRadius cr1, CornerRadius cr2) + { + return (!(cr1 == cr2)); + } + + public double TopLeft + { + get { return _TopLeft; } + set + { + Validate(value, 0, 0, 0); + _TopLeft = value; + } + } + + public double TopRight + { + get { return _TopRight; } + set + { + Validate(0, value, 0, 0); + _TopRight = value; + } + } + + public double BottomRight + { + get { return _BottomRight; } + set + { + Validate(0, 0, value, 0); + _BottomRight = value; + } + } + + public double BottomLeft + { + get { return _BottomLeft; } + set + { + Validate(0, 0, 0, value); + _BottomLeft = value; + } + } + } + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] +#if EMBED + internal +#else + public +#endif + enum GridUnitType + { + Auto = 0, + Pixel, + Star, + } + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.GridLength))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct GridLength + { + private readonly double _unitValue; + private readonly GridUnitType _unitType; + + private const double Default = 1.0; + private static readonly GridLength s_auto = new GridLength(Default, GridUnitType.Auto); + + public GridLength(double pixels) + : this(pixels, GridUnitType.Pixel) + { + } + + internal static bool IsFinite(double value) + { + return !(double.IsNaN(value) || double.IsInfinity(value)); + } + + public GridLength(double value, GridUnitType type) + { + if (!IsFinite(value) || value < 0.0) + { + throw new ArgumentException(SR.DirectUI_InvalidArgument, nameof(value)); + } + if (type != GridUnitType.Auto && type != GridUnitType.Pixel && type != GridUnitType.Star) + { + throw new ArgumentException(SR.DirectUI_InvalidArgument, nameof(type)); + } + + _unitValue = (type == GridUnitType.Auto) ? Default : value; + _unitType = type; + } + + + public double Value { get { return ((_unitType == GridUnitType.Auto) ? s_auto._unitValue : _unitValue); } } + public GridUnitType GridUnitType { get { return (_unitType); } } + + + public bool IsAbsolute { get { return (_unitType == GridUnitType.Pixel); } } + public bool IsAuto { get { return (_unitType == GridUnitType.Auto); } } + public bool IsStar { get { return (_unitType == GridUnitType.Star); } } + + public static GridLength Auto + { + get { return (s_auto); } + } + + + public static bool operator ==(GridLength gl1, GridLength gl2) + { + return (gl1.GridUnitType == gl2.GridUnitType + && gl1.Value == gl2.Value); + } + + public static bool operator !=(GridLength gl1, GridLength gl2) + { + return (gl1.GridUnitType != gl2.GridUnitType + || gl1.Value != gl2.Value); + } + + public override bool Equals(object oCompare) + { + if (oCompare is GridLength) + { + GridLength l = (GridLength)oCompare; + return (this == l); + } + else + return false; + } + + public bool Equals(GridLength gridLength) + { + return (this == gridLength); + } + + public override int GetHashCode() + { + return ((int)_unitValue + (int)_unitType); + } + + public override string ToString() + { + return this.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + + internal string ToString(global::System.Globalization.CultureInfo cultureInfo) + { + char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo); + + // Initial capacity [64] is an estimate based on a sum of: + // 12 = 1x double (twelve digits is generous for the range of values likely) + // 8 = 4x Unit Type string (approx two characters) + // 2 = 2x separator characters + + if (_unitType == GridUnitType.Auto) + { + return "Auto"; + } + else if (_unitType == GridUnitType.Pixel) + { + return Convert.ToString(_unitValue, cultureInfo); + } + else + { + return Convert.ToString(_unitValue, cultureInfo) + "*"; + } + } + } + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Thickness))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct Thickness + { + private double _Left; + private double _Top; + private double _Right; + private double _Bottom; + + public Thickness(double uniformLength) + { + _Left = _Top = _Right = _Bottom = uniformLength; + } + + public Thickness(double left, double top, double right, double bottom) + { + _Left = left; + _Top = top; + _Right = right; + _Bottom = bottom; + } + + public double Left + { + get { return _Left; } + set { _Left = value; } + } + + public double Top + { + get { return _Top; } + set { _Top = value; } + } + + public double Right + { + get { return _Right; } + set { _Right = value; } + } + + public double Bottom + { + get { return _Bottom; } + set { _Bottom = value; } + } + + public override string ToString() + { + return ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + + internal string ToString(global::System.Globalization.CultureInfo cultureInfo) + { + char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo); + + // Initial capacity [64] is an estimate based on a sum of: + // 48 = 4x double (twelve digits is generous for the range of values likely) + // 8 = 4x Unit Type string (approx two characters) + // 4 = 4x separator characters + global::System.Text.StringBuilder sb = new global::System.Text.StringBuilder(64); + + sb.Append(InternalToString(_Left, cultureInfo)); + sb.Append(listSeparator); + sb.Append(InternalToString(_Top, cultureInfo)); + sb.Append(listSeparator); + sb.Append(InternalToString(_Right, cultureInfo)); + sb.Append(listSeparator); + sb.Append(InternalToString(_Bottom, cultureInfo)); + return sb.ToString(); + } + + internal string InternalToString(double l, global::System.Globalization.CultureInfo cultureInfo) + { + if (double.IsNaN(l)) return "Auto"; + return Convert.ToString(l, cultureInfo); + } + + public override bool Equals(object obj) + { + if (obj is Thickness) + { + Thickness otherObj = (Thickness)obj; + return (this == otherObj); + } + return (false); + } + + public bool Equals(Thickness thickness) + { + return (this == thickness); + } + + public override int GetHashCode() + { + return _Left.GetHashCode() ^ _Top.GetHashCode() ^ _Right.GetHashCode() ^ _Bottom.GetHashCode(); + } + + public static bool operator ==(Thickness t1, Thickness t2) + { + return t1._Left == t2._Left && t1._Top == t2._Top && t1._Right == t2._Right && t1._Bottom == t2._Bottom; + } + + public static bool operator !=(Thickness t1, Thickness t2) + { + return (!(t1 == t2)); + } + } + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] +#if EMBED + internal +#else + public +#endif + enum DurationType + { + Automatic, + TimeSpan, + Forever + } + + [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Duration))] + [StructLayout(LayoutKind.Sequential)] +#if EMBED + internal +#else + public +#endif + struct Duration + { + private readonly TimeSpan _timeSpan; + private DurationType _durationType; + + public Duration(TimeSpan timeSpan) + { + _durationType = DurationType.TimeSpan; + _timeSpan = timeSpan; + } + + public static implicit operator Duration(TimeSpan timeSpan) + { + return new Duration(timeSpan); + } + + public static Duration operator +(Duration t1, Duration t2) + { + if (t1.HasTimeSpan && t2.HasTimeSpan) + { + return new Duration(t1._timeSpan + t2._timeSpan); + } + else if (t1._durationType != DurationType.Automatic && t2._durationType != DurationType.Automatic) + { + return Duration.Forever; + } + else + { + // Automatic + anything is Automatic + return Duration.Automatic; + } + } + + public static Duration operator -(Duration t1, Duration t2) + { + if (t1.HasTimeSpan && t2.HasTimeSpan) + { + return new Duration(t1._timeSpan - t2._timeSpan); + } + else if (t1._durationType == DurationType.Forever && t2.HasTimeSpan) + { + return Duration.Forever; + } + else + { + return Duration.Automatic; + } + } + + public static bool operator ==(Duration t1, Duration t2) + { + return t1.Equals(t2); + } + + public static bool operator !=(Duration t1, Duration t2) + { + return !(t1.Equals(t2)); + } + + public static bool operator >(Duration t1, Duration t2) + { + if (t1.HasTimeSpan && t2.HasTimeSpan) + { + return t1._timeSpan > t2._timeSpan; + } + else if (t1.HasTimeSpan && t2._durationType == DurationType.Forever) + { + return false; + } + else if (t1._durationType == DurationType.Forever && t2.HasTimeSpan) + { + return true; + } + else + { + return false; + } + } + + public static bool operator >=(Duration t1, Duration t2) + { + if (t1._durationType == DurationType.Automatic && t2._durationType == DurationType.Automatic) + { + return true; + } + else if (t1._durationType == DurationType.Automatic || t2._durationType == DurationType.Automatic) + { + return false; + } + else + { + return !(t1 < t2); + } + } + + public static bool operator <(Duration t1, Duration t2) + { + if (t1.HasTimeSpan && t2.HasTimeSpan) + { + return t1._timeSpan < t2._timeSpan; + } + else if (t1.HasTimeSpan && t2._durationType == DurationType.Forever) + { + return true; + } + else if (t1._durationType == DurationType.Forever && t2.HasTimeSpan) + { + return false; + } + else + { + return false; + } + } + + public static bool operator <=(Duration t1, Duration t2) + { + if (t1._durationType == DurationType.Automatic && t2._durationType == DurationType.Automatic) + { + return true; + } + else if (t1._durationType == DurationType.Automatic || t2._durationType == DurationType.Automatic) + { + return false; + } + else + { + return !(t1 > t2); + } + } + + public static int Compare(Duration t1, Duration t2) + { + if (t1._durationType == DurationType.Automatic) + { + if (t2._durationType == DurationType.Automatic) + { + return 0; + } + else + { + return -1; + } + } + else if (t2._durationType == DurationType.Automatic) + { + return 1; + } + else + { + if (t1 < t2) + { + return -1; + } + else if (t1 > t2) + { + return 1; + } + else + { + return 0; + } + } + } + + public static Duration operator +(Duration duration) + { + return duration; + } + + public bool HasTimeSpan + { + get + { + return _durationType == DurationType.TimeSpan; + } + } + + public static Duration Automatic + { + get + { + Duration duration = default; + duration._durationType = DurationType.Automatic; + + return duration; + } + } + + public static Duration Forever + { + get + { + Duration duration = default; + duration._durationType = DurationType.Forever; + + return duration; + } + } + + public TimeSpan TimeSpan + { + get + { + if (HasTimeSpan) + { + return _timeSpan; + } + else + { + throw new InvalidOperationException(); + } + } + } + + public Duration Add(Duration duration) + { + return this + duration; + } + + public override bool Equals(object value) + { + return value is Duration && Equals((Duration)value); + } + + public bool Equals(Duration duration) + { + if (HasTimeSpan) + { + if (duration.HasTimeSpan) + { + return _timeSpan == duration._timeSpan; + } + else + { + return false; + } + } + else + { + return _durationType == duration._durationType; + } + } + + public static bool Equals(Duration t1, Duration t2) + { + return t1.Equals(t2); + } + + public override int GetHashCode() + { + if (HasTimeSpan) + { + return _timeSpan.GetHashCode(); + } + else + { + return _durationType.GetHashCode() + 17; + } + } + + public Duration Subtract(Duration duration) + { + return this - duration; + } + + public override string ToString() + { + if (HasTimeSpan) + { + return _timeSpan.ToString(); // "00"; //TypeDescriptor.GetConverter(_timeSpan).ConvertToString(_timeSpan); + } + else if (_durationType == DurationType.Forever) + { + return "Forever"; + } + else // IsAutomatic + { + return "Automatic"; + } + } + } +} + +namespace ABI.Windows.UI.Xaml +{ +#if EMBED + internal +#else + public +#endif + static class CornerRadius + { + public static string GetGuidSignature() => $"struct(Windows.UI.Xaml.CornerRadius;f8;f8;f8;f8)"; + } + +#if EMBED + internal +#else + public +#endif + static class Duration + { + public static string GetGuidSignature() + { + string timeSpanSignature = global::WinRT.GuidGenerator.GetSignature(typeof(global::System.TimeSpan)); + string durationTypeSignature = global::WinRT.GuidGenerator.GetSignature(typeof(global::Windows.UI.Xaml.DurationType)); + return $"struct(Windows.UI.Xaml.Duration;{timeSpanSignature};{durationTypeSignature})"; + } + } + +#if EMBED + internal +#else + public +#endif + static class DurationType + { + public static string GetGuidSignature() => "enum(Windows.UI.Xaml.DurationType;i4)"; + } + +#if EMBED + internal +#else + public +#endif + static class GridLength + { + public static string GetGuidSignature() + { + string unitTypeSignature = global::WinRT.GuidGenerator.GetSignature(typeof(global::Windows.UI.Xaml.GridUnitType)); + return $"struct(Windows.UI.Xaml.GridLength;f8;{unitTypeSignature})"; + } + } + +#if EMBED + internal +#else + public +#endif + static class GridUnitType + { + public static string GetGuidSignature() => "enum(Windows.UI.Xaml.GridUnitType;i4)"; + } + +#if EMBED + internal +#else + public +#endif + static class Thickness + { + public static string GetGuidSignature() => $"struct(Windows.UI.Xaml.Thickness;f8;f8;f8;f8)"; + } +}