diff --git a/src/Benchmarks/Benchmarks/CollectionsPerf.cs b/src/Benchmarks/Benchmarks/CollectionsPerf.cs index 612b3bc11..2b9261cf3 100644 --- a/src/Benchmarks/Benchmarks/CollectionsPerf.cs +++ b/src/Benchmarks/Benchmarks/CollectionsPerf.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using BenchmarkComponent; using BenchmarkDotNet.Attributes; @@ -19,8 +20,13 @@ public class CollectionsPerf private IList vector; private IList bulkVector; private int[] bulkBuffer; + private int[] managedBulkVector; + private ClassWithMarshalingRoutines instance; + private IList bulkStringVector; + private string[] bulkStringBuffer; private IDictionary stringMap; private IReadOnlyList vectorView; + private IReadOnlyList bulkVectorView; private IReadOnlyDictionary mapView; private IList objectVector; @@ -28,18 +34,33 @@ public class CollectionsPerf private WrappedClass[] bulkObjectBuffer; private IDictionary objectMap; private IReadOnlyList objectVectorView; + private IReadOnlyList bulkObjectVectorView; private IReadOnlyDictionary objectMapView; [GlobalSetup] public void Setup() { - ClassWithMarshalingRoutines instance = new(); + instance = new(); vector = instance.Items(VectorLen); bulkVector = instance.Items(BulkCount); bulkBuffer = new int[BulkCount]; + managedBulkVector = new int[BulkCount]; + for (int i = 0; i < BulkCount; i++) + { + managedBulkVector[i] = i; + } + // Will be uncommented once the TestWinRT change is done. + // _ = instance.GetManyFromManagedList(managedBulkVector); + bulkStringVector = instance.NewList(); + bulkStringBuffer = new string[BulkCount]; + for (int i = 0; i < BulkCount; i++) + { + bulkStringVector.Add(i.ToString()); + } stringMap = instance.StringMap(MapLen); vectorView = instance.ItemsView(VectorLen); + bulkVectorView = instance.ItemsView(BulkCount); mapView = instance.MapView(MapLen); objectVector = instance.ObjectItems(VectorLen); @@ -47,6 +68,7 @@ public void Setup() bulkObjectBuffer = new WrappedClass[BulkCount]; objectMap = instance.ObjectMap(MapLen); objectVectorView = instance.ObjectItemsView(VectorLen); + bulkObjectVectorView = instance.ObjectItemsView(BulkCount); objectMapView = instance.ObjectMapView(MapLen); } @@ -89,12 +111,55 @@ public void GetMany() bulkVector.CopyTo(bulkBuffer, 0); } + // Will be uncommented once the TestWinRT change is done. + // [Benchmark(OperationsPerInvoke = BulkCount)] + // public uint GetManyFromManagedList() + // { + // return instance.GetManyFromManagedList(managedBulkVector); + // } + + [Benchmark(OperationsPerInvoke = BulkCount)] + public void GetManyStrings() + { + bulkStringVector.CopyTo(bulkStringBuffer, 0); + } + [Benchmark(OperationsPerInvoke = BulkCount)] public void GetManyObjects() { bulkObjectVector.CopyTo(bulkObjectBuffer, 0); } + [Benchmark(OperationsPerInvoke = BulkCount)] + public int[] ToArray() + { + return bulkVector.ToArray(); + } + + [Benchmark(OperationsPerInvoke = BulkCount)] + public string[] ToArrayStrings() + { + return bulkStringVector.ToArray(); + } + + [Benchmark(OperationsPerInvoke = BulkCount)] + public WrappedClass[] ToArrayObjects() + { + return bulkObjectVector.ToArray(); + } + + [Benchmark(OperationsPerInvoke = BulkCount)] + public int[] ToArrayView() + { + return bulkVectorView.ToArray(); + } + + [Benchmark(OperationsPerInvoke = BulkCount)] + public WrappedClass[] ToArrayViewObjects() + { + return bulkObjectVectorView.ToArray(); + } + [Benchmark(OperationsPerInvoke = MapLen)] public int Map() { diff --git a/src/Tests/TestComponentCSharp/Class.cpp b/src/Tests/TestComponentCSharp/Class.cpp index 557eae1b9..1adf0c363 100644 --- a/src/Tests/TestComponentCSharp/Class.cpp +++ b/src/Tests/TestComponentCSharp/Class.cpp @@ -1203,6 +1203,39 @@ namespace winrt::TestComponentCSharp::implementation }); } + IVector Class::GetStringVector2() + { + std::vector values; + values.reserve(130); + + for (int32_t i = 0; i < 130; i++) + { + values.push_back(to_hstring(i)); + } + + return winrt::single_threaded_vector(std::move(values)); + } + + IVector Class::GetDateTimeVector2() + { + auto now = winrt::clock::now(); + return winrt::single_threaded_vector(std::vector{ now, now + std::chrono::seconds{ 1 } }); + } + + IVector Class::GetClassVector2() + { + return winrt::single_threaded_vector(std::vector + { + winrt::make(), + winrt::make(), + }); + } + + IVector Class::GetExceptionVector2() + { + return winrt::single_threaded_vector(std::vector{ winrt::hresult{ -2147467259 }, winrt::hresult{ -2147024809 } }); + } + // Test IIDOptimizer IVectorView Class::GetEventArgsVector() { @@ -2034,6 +2067,20 @@ namespace winrt::TestComponentCSharp::implementation return sum; } + int64_t Class::SumIntsWithGetMany(IVector const& values, uint32_t startIndex, uint32_t capacity) + { + std::vector items(capacity); + uint32_t retrieved = values.GetMany(startIndex, items); + int64_t sum = 0; + + for (uint32_t i = 0; i < retrieved; i++) + { + sum += items[i]; + } + + return sum; + } + int32_t Class::CountKeyValuePairsWithGetMany(winrt::Windows::Foundation::Collections::IIterable> const& pairs) { auto iterator = pairs.First(); @@ -2210,4 +2257,3 @@ namespace winrt::TestComponentCSharp::implementation return winrt::make(); } } - diff --git a/src/Tests/TestComponentCSharp/Class.h b/src/Tests/TestComponentCSharp/Class.h index 557270389..9c93e49f3 100644 --- a/src/Tests/TestComponentCSharp/Class.h +++ b/src/Tests/TestComponentCSharp/Class.h @@ -292,6 +292,10 @@ namespace winrt::TestComponentCSharp::implementation Windows::Foundation::Collections::IVector GetIntVector2(); Windows::Foundation::Collections::IVector GetBlittableStructVector2(); Windows::Foundation::Collections::IVector GetNonBlittableStructVector2(); + Windows::Foundation::Collections::IVector GetStringVector2(); + Windows::Foundation::Collections::IVector GetDateTimeVector2(); + Windows::Foundation::Collections::IVector GetClassVector2(); + Windows::Foundation::Collections::IVector GetExceptionVector2(); Windows::Foundation::Collections::IMap GetIntToIntDictionary(); Windows::Foundation::Collections::IMap GetStringToBlittableDictionary(); @@ -427,6 +431,7 @@ namespace winrt::TestComponentCSharp::implementation double Calculate(winrt::Windows::Foundation::Collections::IVector> const& values); winrt::Windows::Foundation::Collections::IVector> GetNullableIntList(); int32_t SumNullableIntsWithGetMany(winrt::Windows::Foundation::Collections::IVector> const& values); + int64_t SumIntsWithGetMany(winrt::Windows::Foundation::Collections::IVector const& values, uint32_t startIndex, uint32_t capacity); int32_t CountKeyValuePairsWithGetMany(winrt::Windows::Foundation::Collections::IIterable> const& pairs); static int GetPropertyType(Windows::Foundation::IInspectable const& obj); diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index ac08a3aa9..12a147520 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -383,6 +383,10 @@ namespace TestComponentCSharp Windows.Foundation.Collections.IVector GetIntVector2(); Windows.Foundation.Collections.IVector GetBlittableStructVector2(); Windows.Foundation.Collections.IVector GetNonBlittableStructVector2(); + Windows.Foundation.Collections.IVector GetStringVector2(); + Windows.Foundation.Collections.IVector GetDateTimeVector2(); + Windows.Foundation.Collections.IVector GetClassVector2(); + Windows.Foundation.Collections.IVector GetExceptionVector2(); Windows.Foundation.Collections.IMap GetIntToIntDictionary(); Windows.Foundation.Collections.IMap GetStringToBlittableDictionary(); @@ -480,6 +484,7 @@ namespace TestComponentCSharp Double Calculate(Windows.Foundation.Collections.IVector > values); Windows.Foundation.Collections.IVector > GetNullableIntList(); Int32 SumNullableIntsWithGetMany(Windows.Foundation.Collections.IVector > values); + Int64 SumIntsWithGetMany(Windows.Foundation.Collections.IVector values, UInt32 startIndex, UInt32 capacity); Int32 CountKeyValuePairsWithGetMany(Windows.Foundation.Collections.IIterable > pairs); // Boxing diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 7b66a2ec7..0dcd7aa97 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -3964,6 +3964,101 @@ public void TestListOfTypes() Assert.AreEqual(2, types.Count); Assert.AreEqual(typeof(Class), types[0]); Assert.AreEqual(typeof(int?), types[1]); + + Type[] copied = new Type[3]; + types.CopyTo(copied, 1); + Assert.IsNull(copied[0]); + Assert.AreEqual(typeof(Class), copied[1]); + Assert.AreEqual(typeof(int?), copied[2]); + } + + [TestMethod] + public void NativeVectorCopyTo_ValueTypes() + { + IList ints = TestObject.GetIntVector2(); + int[] copiedInts = new int[ints.Count + 1]; + ints.CopyTo(copiedInts, 1); + CollectionAssert.AreEqual(new[] { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, copiedInts); + + IList blittableStructs = TestObject.GetBlittableStructVector2(); + ComposedBlittableStruct[] copiedBlittableStructs = new ComposedBlittableStruct[blittableStructs.Count]; + blittableStructs.CopyTo(copiedBlittableStructs, 0); + Assert.AreEqual(4, copiedBlittableStructs[4].blittable.i32); + + IList nonBlittableStructs = TestObject.GetNonBlittableStructVector2(); + ComposedNonBlittableStruct[] copiedNonBlittableStructs = new ComposedNonBlittableStruct[nonBlittableStructs.Count]; + nonBlittableStructs.CopyTo(copiedNonBlittableStructs, 0); + Assert.AreEqual("String1", copiedNonBlittableStructs[1].strings.str); + Assert.IsTrue(copiedNonBlittableStructs[2].bools.w); + + IList dateTimes = TestObject.GetDateTimeVector2(); + DateTimeOffset[] copiedDateTimes = new DateTimeOffset[dateTimes.Count]; + dateTimes.CopyTo(copiedDateTimes, 0); + Assert.AreEqual(TimeSpan.FromSeconds(1), copiedDateTimes[1] - copiedDateTimes[0]); + } + + [TestMethod] + public void NativeVectorCopyTo_ReferenceTypes() + { + IList classes = TestObject.GetClassVector2(); + Class[] copiedClasses = new Class[classes.Count + 1]; + classes.CopyTo(copiedClasses, 1); + Assert.IsNull(copiedClasses[0]); + Assert.IsNotNull(copiedClasses[1]); + Assert.IsNotNull(copiedClasses[2]); + + IList objects = TestObject.GetUriVectorAsIInspectableVector(); + object[] copiedObjects = new object[objects.Count]; + objects.CopyTo(copiedObjects, 0); + Assert.IsTrue(copiedObjects.All(static item => item is Uri)); + } + + [TestMethod] + public void NativeVectorCopyTo_StringTypeAcrossChunks() + { + IList strings = TestObject.GetStringVector2(); + string[] copiedStrings = new string[strings.Count + 2]; + strings.CopyTo(copiedStrings, 1); + Assert.IsNull(copiedStrings[0]); + Assert.AreEqual("0", copiedStrings[1]); + Assert.AreEqual("64", copiedStrings[65]); + Assert.AreEqual("129", copiedStrings[130]); + Assert.IsNull(copiedStrings[131]); + } + + [TestMethod] + public void NativeVectorCopyTo_NullableType() + { + IList nullableInts = TestObject.GetNullableIntList(); + int?[] copiedNullableInts = new int?[nullableInts.Count]; + nullableInts.CopyTo(copiedNullableInts, 0); + CollectionAssert.AreEqual(new int?[] { 1, null, 2 }, copiedNullableInts); + } + + [TestMethod] + public void NativeVectorCopyTo_ExceptionType() + { + IList exceptions = TestObject.GetExceptionVector2(); + Exception[] copiedExceptions = new Exception[exceptions.Count]; + exceptions.CopyTo(copiedExceptions, 0); + Assert.AreEqual(unchecked((int)0x80004005), copiedExceptions[0].HResult); + Assert.AreEqual(unchecked((int)0x80070057), copiedExceptions[1].HResult); + } + + [TestMethod] + public void ManagedVectorGetMany_BlittableFastPathsAndFallback() + { + int[] array = [10, 20, 30, 40, 50]; + Assert.AreEqual(90L, TestObject.SumIntsWithGetMany(array, 1, 3)); + + List list = [10, 20, 30, 40, 50]; + Assert.AreEqual(90L, TestObject.SumIntsWithGetMany(list, 1, 3)); + + Collection collection = [10, 20, 30, 40, 50]; + Assert.AreEqual(90L, TestObject.SumIntsWithGetMany(collection, 1, 3)); + + Assert.AreEqual(0L, TestObject.SumIntsWithGetMany(array, (uint)array.Length, 3)); + Assert.AreEqual(0L, TestObject.SumIntsWithGetMany(array, 0, 0)); } [TestMethod] diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs index 515977fb5..8bf475509 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs @@ -154,6 +154,17 @@ public static void IVectorMethods( declaration: interopReferences.IVectorMethodsImpl1GetAt(elementType), method: getAtMethod); + // Define the 'GetMany' method + MethodDefinition getManyMethod = InteropMethodDefinitionFactory.IVectorMethods.GetMany( + listType: listType, + interopReferences: interopReferences, + emitState: emitState); + + // Add and implement the 'GetMany' method + vectorMethodsType.AddMethodImplementation( + declaration: interopReferences.IVectorMethodsImpl1GetMany(elementType), + method: getManyMethod); + // Define the 'SetAt' method MethodDefinition setAtMethod = InteropMethodDefinitionFactory.IVectorMethods.SetAt( listType: listType, diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IVectorMethods.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IVectorMethods.cs index 0ac7c2636..77c133a65 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IVectorMethods.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IVectorMethods.cs @@ -21,6 +21,74 @@ internal partial class InteropMethodDefinitionFactory /// public static class IVectorMethods { + /// + /// Creates a for the GetMany method for some IVector<T> interface. + /// + /// The for the type. + /// The instance to use. + /// The emit state for this invocation. + public static MethodDefinition GetMany( + GenericInstanceTypeSignature listType, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState) + { + TypeSignature elementType = listType.TypeArguments[0]; + + // Get the appropriate 'GetMany' method descriptor for 'IVector' types + IMethodDescriptor getManyMethod = elementType switch + { + _ when elementType.IsBlittable(interopReferences) => interopReferences.IVectorMethodsBlittableValueTypeGetMany(elementType), + _ when elementType.IsConstructedKeyValuePairType(interopReferences) => interopReferences.IVectorMethodsKeyValuePairTypeGetMany( + keyType: ((GenericInstanceTypeSignature)elementType).TypeArguments[0], + valueType: ((GenericInstanceTypeSignature)elementType).TypeArguments[1], + elementMarshallerType: emitState.LookupTypeDefinition(elementType, "ElementMarshaller").ToTypeSignature()), + _ when elementType.IsConstructedNullableValueType(interopReferences) => interopReferences.IVectorMethodsNullableTypeGetMany( + underlyingType: ((GenericInstanceTypeSignature)elementType).TypeArguments[0], + elementMarshallerType: emitState.LookupTypeDefinition(elementType, "ElementMarshaller").ToTypeSignature()), + _ when elementType.IsManagedValueType(interopReferences) => interopReferences.IVectorMethodsManagedValueTypeGetMany( + elementType: elementType, + abiType: elementType.GetAbiType(interopReferences), + elementMarshallerType: emitState.LookupTypeDefinition(elementType, "ElementMarshaller").ToTypeSignature()), + _ when elementType.IsValueType => interopReferences.IVectorMethodsUnmanagedValueTypeGetMany( + elementType: elementType, + abiType: elementType.GetAbiType(interopReferences), + elementMarshallerType: emitState.LookupTypeDefinition(elementType, "ElementMarshaller").ToTypeSignature()), + _ when elementType.IsTypeOfObject() => interopReferences.IVectorMethodsOfObjectGetMany, + _ when elementType.IsTypeOfString() => interopReferences.IVectorMethodsOfStringGetMany, + _ when elementType.IsTypeOfType(interopReferences) => interopReferences.IVectorMethodsOfTypeGetMany, + _ when elementType.IsTypeOfException(interopReferences) => interopReferences.IVectorMethodsOfExceptionGetMany, + _ => interopReferences.IVectorMethodsReferenceTypeGetMany( + elementType: elementType, + elementMarshallerType: emitState.LookupTypeDefinition(elementType, "ElementMarshaller").ToTypeSignature()) + }; + + // Define the 'GetMany' method as follows: + // + // public static int GetMany(WindowsRuntimeObjectReference thisReference, [] array, int arrayIndex, int count) + return new( + name: "GetMany"u8, + attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + signature: MethodSignature.CreateStatic( + returnType: interopReferences.Int32, + parameterTypes: [ + interopReferences.WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + elementType.MakeSzArrayType(), + interopReferences.Int32, + interopReferences.Int32])) + { + CilInstructions = + { + // return (thisReference, array, arrayIndex, count); + { Ldarg_0 }, + { Ldarg_1 }, + { Ldarg_2 }, + { Ldarg_3 }, + { Call, getManyMethod }, + { Ret } + } + }; + } + /// /// Creates a for the SetAt method for some IVector<T> interface. /// @@ -416,4 +484,4 @@ private static MethodDefinition SetAtOrInsertAt( return setAtOrInsertAtMethod; } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.cs b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.cs index eca50d9d0..3ad6112c7 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.cs @@ -46,7 +46,7 @@ public static TypeDefinition UnmanagedValueType( .IWindowsRuntimeUnmanagedValueTypeElementMarshaller2 .MakeGenericReferenceType([elementType, elementAbiType]); - return ElementMarshaller( + TypeDefinition elementMarshallerType = ElementMarshaller( elementType: elementType, interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeUnmanagedValueTypeElementMarshallerConvertToUnmanaged(elementType, elementAbiType), @@ -54,6 +54,16 @@ public static TypeDefinition UnmanagedValueType( interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); + + // Add the 'ConvertToManaged' method (unmanaged value types have nothing to dispose) + ConvertToManaged( + elementMarshallerType: elementMarshallerType, + elementType: elementType, + elementAbiType: elementAbiType, + convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeUnmanagedValueTypeElementMarshallerConvertToManaged(elementType, elementAbiType), + emitState: emitState); + + return elementMarshallerType; } /// @@ -88,6 +98,14 @@ public static TypeDefinition ManagedValueType( interopReferences: interopReferences, emitState: emitState); + // Add the 'ConvertToManaged' method + ConvertToManaged( + elementMarshallerType: elementMarshallerType, + elementType: elementType, + elementAbiType: elementAbiType, + convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeManagedValueTypeElementMarshallerConvertToManaged(elementType, elementAbiType), + emitState: emitState); + // Rewriting labels CilInstruction nop_dispose = new(Nop); @@ -147,7 +165,7 @@ public static TypeDefinition KeyValuePair( // Specialize if both type arguments are value types (same logic as in the array element marshaller) bool isValueType = keyType.IsValueType && valueType.IsValueType; - return ElementMarshaller( + TypeDefinition elementMarshallerType = ElementMarshaller( elementType: elementType, interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeKeyValuePairTypeElementMarshallerConvertToUnmanaged(keyType, valueType), @@ -155,6 +173,17 @@ public static TypeDefinition KeyValuePair( interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); + + // Add the 'ConvertToManaged' and 'Dispose' methods + ConvertToManagedAndDispose( + elementMarshallerType: elementMarshallerType, + elementType: elementType, + convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeKeyValuePairTypeElementMarshallerConvertToManaged(keyType, valueType), + disposeInterfaceMethod: interopReferences.IWindowsRuntimeKeyValuePairTypeElementMarshallerDispose(keyType, valueType), + interopReferences: interopReferences, + emitState: emitState); + + return elementMarshallerType; } /// @@ -179,7 +208,7 @@ public static TypeDefinition NullableValueType( .IWindowsRuntimeNullableTypeElementMarshaller1 .MakeGenericReferenceType([underlyingType]); - return ElementMarshaller( + TypeDefinition elementMarshallerType = ElementMarshaller( elementType: elementType, interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeNullableTypeElementMarshallerConvertToUnmanaged(underlyingType), @@ -187,6 +216,17 @@ public static TypeDefinition NullableValueType( interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); + + // Add the 'ConvertToManaged' and 'Dispose' methods + ConvertToManagedAndDispose( + elementMarshallerType: elementMarshallerType, + elementType: elementType, + convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeNullableTypeElementMarshallerConvertToManaged(underlyingType), + disposeInterfaceMethod: interopReferences.IWindowsRuntimeNullableTypeElementMarshallerDispose(underlyingType), + interopReferences: interopReferences, + emitState: emitState); + + return elementMarshallerType; } /// @@ -210,7 +250,7 @@ public static TypeDefinition ReferenceType( .IWindowsRuntimeReferenceTypeElementMarshaller1 .MakeGenericReferenceType([elementType]); - return ElementMarshaller( + TypeDefinition elementMarshallerType = ElementMarshaller( elementType: elementType, interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeReferenceTypeElementMarshallerConvertToUnmanaged(elementType), @@ -218,6 +258,115 @@ public static TypeDefinition ReferenceType( interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); + + // Add the 'ConvertToManaged' and 'Dispose' methods + ConvertToManagedAndDispose( + elementMarshallerType: elementMarshallerType, + elementType: elementType, + convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeReferenceTypeElementMarshallerConvertToManaged(elementType), + disposeInterfaceMethod: interopReferences.IWindowsRuntimeReferenceTypeElementMarshallerDispose(elementType), + interopReferences: interopReferences, + emitState: emitState); + + return elementMarshallerType; + } + + /// + /// Adds the ConvertToManaged method to an element marshaller type. + /// + /// The element marshaller type to add the method to. + /// The for the element type. + /// The ABI type for . + /// The ConvertToManaged interface method being implemented. + /// The emit state for this invocation. + private static void ConvertToManaged( + TypeDefinition elementMarshallerType, + TypeSignature elementType, + TypeSignature elementAbiType, + MemberReference convertToManagedInterfaceMethod, + InteropGeneratorEmitState emitState) + { + // Rewriting labels + CilInstruction nop_convertToManaged = new(Nop); + + // Define the 'ConvertToManaged' method as follows: + // + // public static ConvertToManaged( value) + MethodDefinition convertToManagedMethod = new( + name: "ConvertToManaged"u8, + attributes: MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, + signature: MethodSignature.CreateStatic( + returnType: elementType, + parameterTypes: [elementAbiType])) + { + CilInstructions = + { + { nop_convertToManaged }, + { Ret } + } + }; + + // Add and implement the 'ConvertToManaged' method + elementMarshallerType.AddMethodImplementation( + declaration: convertToManagedInterfaceMethod, + method: convertToManagedMethod); + + // Track rewriting the managed value for 'ConvertToManaged' + emitState.TrackManagedParameterMethodRewrite( + parameterType: elementType, + method: convertToManagedMethod, + marker: nop_convertToManaged, + parameterIndex: 0); + } + + /// + /// Adds the ConvertToManaged and Dispose methods to an element marshaller type for an element type marshalled as a native object. + /// + /// The element marshaller type to add the methods to. + /// The for the element type. + /// The ConvertToManaged interface method being implemented. + /// The Dispose interface method being implemented. + /// The instance to use. + /// The emit state for this invocation. + private static void ConvertToManagedAndDispose( + TypeDefinition elementMarshallerType, + TypeSignature elementType, + MemberReference convertToManagedInterfaceMethod, + MemberReference disposeInterfaceMethod, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState) + { + // These element types are all marshalled as native object pointers + ConvertToManaged( + elementMarshallerType: elementMarshallerType, + elementType: elementType, + elementAbiType: interopReferences.Void.MakePointerType(), + convertToManagedInterfaceMethod: convertToManagedInterfaceMethod, + emitState: emitState); + + // Define the 'Dispose' method as follows: + // + // public static void Dispose(void* value) + MethodDefinition disposeMethod = new( + name: "Dispose"u8, + attributes: MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, + signature: MethodSignature.CreateStatic( + returnType: interopReferences.Void, + parameterTypes: [interopReferences.Void.MakePointerType()])) + { + CilInstructions = + { + // WindowsRuntimeUnknownMarshaller.Free(value); + { Ldarg_0 }, + { Call, interopReferences.WindowsRuntimeUnknownMarshallerFree }, + { Ret } + } + }; + + // Add and implement the 'Dispose' method + elementMarshallerType.AddMethodImplementation( + declaration: disposeInterfaceMethod, + method: disposeMethod); } /// diff --git a/src/WinRT.Interop.Generator/References/InteropReferences.cs b/src/WinRT.Interop.Generator/References/InteropReferences.cs index 9ec993d28..a47b60f3f 100644 --- a/src/WinRT.Interop.Generator/References/InteropReferences.cs +++ b/src/WinRT.Interop.Generator/References/InteropReferences.cs @@ -890,6 +890,41 @@ public InteropReferences( /// public TypeReference IVectorMethodsImpl1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsImpl`1"u8); + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsExtensions. + /// + public TypeReference IVectorMethodsExtensions => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsExtensions"u8); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsBlittableValueTypeExtensions. + /// + public TypeReference IVectorMethodsBlittableValueTypeExtensions => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsBlittableValueTypeExtensions"u8); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsUnmanagedValueTypeExtensions. + /// + public TypeReference IVectorMethodsUnmanagedValueTypeExtensions => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsUnmanagedValueTypeExtensions"u8); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsManagedValueTypeExtensions. + /// + public TypeReference IVectorMethodsManagedValueTypeExtensions => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsManagedValueTypeExtensions"u8); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsKeyValuePairTypeExtensions. + /// + public TypeReference IVectorMethodsKeyValuePairTypeExtensions => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsKeyValuePairTypeExtensions"u8); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsNullableTypeExtensions. + /// + public TypeReference IVectorMethodsNullableTypeExtensions => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsNullableTypeExtensions"u8); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsReferenceTypeExtensions. + /// + public TypeReference IVectorMethodsReferenceTypeExtensions => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsReferenceTypeExtensions"u8); + /// /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsImpl<T>. /// @@ -3152,6 +3187,34 @@ public MemberReference IWindowsRuntimeReferenceTypeElementMarshallerConvertToUnm parameterTypes: [new GenericParameterSignature(GenericParameterType.Type, 0)])); } + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeReferenceTypeElementMarshaller<T>.ConvertToManaged. + /// + /// The input element type. + public MemberReference IWindowsRuntimeReferenceTypeElementMarshallerConvertToManaged(TypeSignature elementType) + { + return IWindowsRuntimeReferenceTypeElementMarshaller1 + .MakeGenericReferenceType([elementType]) + .ToTypeDefOrRef() + .CreateMemberReference("ConvertToManaged"u8, MethodSignature.CreateStatic( + returnType: new GenericParameterSignature(GenericParameterType.Type, 0), + parameterTypes: [_corLibTypeFactory.Void.MakePointerType()])); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeReferenceTypeElementMarshaller<T>.Dispose. + /// + /// The input element type. + public MemberReference IWindowsRuntimeReferenceTypeElementMarshallerDispose(TypeSignature elementType) + { + return IWindowsRuntimeReferenceTypeElementMarshaller1 + .MakeGenericReferenceType([elementType]) + .ToTypeDefOrRef() + .CreateMemberReference("Dispose"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Void, + parameterTypes: [_corLibTypeFactory.Void.MakePointerType()])); + } + /// /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeManagedValueTypeElementMarshaller<T, TAbi>.ConvertToUnmanaged. /// @@ -3167,6 +3230,21 @@ public MemberReference IWindowsRuntimeManagedValueTypeElementMarshallerConvertTo parameterTypes: [new GenericParameterSignature(GenericParameterType.Type, 0)])); } + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeManagedValueTypeElementMarshaller<T, TAbi>.ConvertToManaged. + /// + /// The input element type. + /// The ABI type. + public MemberReference IWindowsRuntimeManagedValueTypeElementMarshallerConvertToManaged(TypeSignature elementType, TypeSignature abiType) + { + return IWindowsRuntimeManagedValueTypeElementMarshaller2 + .MakeGenericReferenceType([elementType, abiType]) + .ToTypeDefOrRef() + .CreateMemberReference("ConvertToManaged"u8, MethodSignature.CreateStatic( + returnType: new GenericParameterSignature(GenericParameterType.Type, 0), + parameterTypes: [new GenericParameterSignature(GenericParameterType.Type, 1)])); + } + /// /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeManagedValueTypeElementMarshaller<T, TAbi>.Dispose. /// @@ -3197,6 +3275,21 @@ public MemberReference IWindowsRuntimeUnmanagedValueTypeElementMarshallerConvert parameterTypes: [new GenericParameterSignature(GenericParameterType.Type, 0)])); } + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeUnmanagedValueTypeElementMarshaller<T, TAbi>.ConvertToManaged. + /// + /// The input element type. + /// The ABI type. + public MemberReference IWindowsRuntimeUnmanagedValueTypeElementMarshallerConvertToManaged(TypeSignature elementType, TypeSignature abiType) + { + return IWindowsRuntimeUnmanagedValueTypeElementMarshaller2 + .MakeGenericReferenceType([elementType, abiType]) + .ToTypeDefOrRef() + .CreateMemberReference("ConvertToManaged"u8, MethodSignature.CreateStatic( + returnType: new GenericParameterSignature(GenericParameterType.Type, 0), + parameterTypes: [new GenericParameterSignature(GenericParameterType.Type, 1)])); + } + /// /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeKeyValuePairTypeElementMarshaller<TKey, TValue>.ConvertToUnmanaged. /// @@ -3215,6 +3308,38 @@ public MemberReference IWindowsRuntimeKeyValuePairTypeElementMarshallerConvertTo new GenericParameterSignature(GenericParameterType.Type, 1)])])); } + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeKeyValuePairTypeElementMarshaller<TKey, TValue>.ConvertToManaged. + /// + /// The input key type. + /// The input value type. + public MemberReference IWindowsRuntimeKeyValuePairTypeElementMarshallerConvertToManaged(TypeSignature keyType, TypeSignature valueType) + { + return IWindowsRuntimeKeyValuePairTypeElementMarshaller2 + .MakeGenericReferenceType([keyType, valueType]) + .ToTypeDefOrRef() + .CreateMemberReference("ConvertToManaged"u8, MethodSignature.CreateStatic( + returnType: KeyValuePair2.MakeGenericValueType([ + new GenericParameterSignature(GenericParameterType.Type, 0), + new GenericParameterSignature(GenericParameterType.Type, 1)]), + parameterTypes: [_corLibTypeFactory.Void.MakePointerType()])); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeKeyValuePairTypeElementMarshaller<TKey, TValue>.Dispose. + /// + /// The input key type. + /// The input value type. + public MemberReference IWindowsRuntimeKeyValuePairTypeElementMarshallerDispose(TypeSignature keyType, TypeSignature valueType) + { + return IWindowsRuntimeKeyValuePairTypeElementMarshaller2 + .MakeGenericReferenceType([keyType, valueType]) + .ToTypeDefOrRef() + .CreateMemberReference("Dispose"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Void, + parameterTypes: [_corLibTypeFactory.Void.MakePointerType()])); + } + /// /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeNullableTypeElementMarshaller<T>.ConvertToUnmanaged. /// @@ -3229,6 +3354,34 @@ public MemberReference IWindowsRuntimeNullableTypeElementMarshallerConvertToUnma parameterTypes: [Nullable1.MakeGenericValueType([new GenericParameterSignature(GenericParameterType.Type, 0)])])); } + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeNullableTypeElementMarshaller<T>.ConvertToManaged. + /// + /// The underlying value type. + public MemberReference IWindowsRuntimeNullableTypeElementMarshallerConvertToManaged(TypeSignature underlyingType) + { + return IWindowsRuntimeNullableTypeElementMarshaller1 + .MakeGenericReferenceType([underlyingType]) + .ToTypeDefOrRef() + .CreateMemberReference("ConvertToManaged"u8, MethodSignature.CreateStatic( + returnType: Nullable1.MakeGenericValueType([new GenericParameterSignature(GenericParameterType.Type, 0)]), + parameterTypes: [_corLibTypeFactory.Void.MakePointerType()])); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.IWindowsRuntimeNullableTypeElementMarshaller<T>.Dispose. + /// + /// The underlying value type. + public MemberReference IWindowsRuntimeNullableTypeElementMarshallerDispose(TypeSignature underlyingType) + { + return IWindowsRuntimeNullableTypeElementMarshaller1 + .MakeGenericReferenceType([underlyingType]) + .ToTypeDefOrRef() + .CreateMemberReference("Dispose"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Void, + parameterTypes: [_corLibTypeFactory.Void.MakePointerType()])); + } + /// /// Gets the for WindowsRuntime.InteropServices.Marshalling.WindowsRuntimeBlittableValueTypeArrayMarshaller<T>.ConvertToUnmanaged. /// @@ -4675,6 +4828,190 @@ public MemberReference IVectorMethodsImpl1GetAt(TypeSignature elementType) _corLibTypeFactory.UInt32])); } + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsImpl<T>.GetMany. + /// + /// The input element type. + public MemberReference IVectorMethodsImpl1GetMany(TypeSignature elementType) + { + return IVectorMethodsImpl1 + .MakeGenericReferenceType([elementType]) + .ToTypeDefOrRef() + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + new GenericParameterSignature(GenericParameterType.Type, 0).MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsExtensions.GetMany. + /// + public MemberReference IVectorMethodsOfStringGetMany => field ??= IVectorMethodsExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + _corLibTypeFactory.String.MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsExtensions.GetMany. + /// + public MemberReference IVectorMethodsOfObjectGetMany => field ??= IVectorMethodsExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + Object.MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsExtensions.GetMany. + /// + public MemberReference IVectorMethodsOfExceptionGetMany => field ??= IVectorMethodsExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + Exception.ToReferenceTypeSignature().MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsExtensions.GetMany. + /// + public MemberReference IVectorMethodsOfTypeGetMany => field ??= IVectorMethodsExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + Type.ToReferenceTypeSignature().MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])); + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsBlittableValueTypeExtensions.GetMany<T>. + /// + /// The input element type. + public MethodSpecification IVectorMethodsBlittableValueTypeGetMany(TypeSignature elementType) + { + return IVectorMethodsBlittableValueTypeExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + genericParameterCount: 1, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + new GenericParameterSignature(GenericParameterType.Method, 0).MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])) + .MakeGenericInstanceMethod([elementType]); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsUnmanagedValueTypeExtensions.GetMany<T, TAbi, TElementMarshaller>. + /// + /// The input element type. + /// The ABI type. + /// The element marshaller type. + public MethodSpecification IVectorMethodsUnmanagedValueTypeGetMany(TypeSignature elementType, TypeSignature abiType, TypeSignature elementMarshallerType) + { + return IVectorMethodsUnmanagedValueTypeExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + genericParameterCount: 3, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + new GenericParameterSignature(GenericParameterType.Method, 0).MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])) + .MakeGenericInstanceMethod([elementType, abiType, elementMarshallerType]); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsManagedValueTypeExtensions.GetMany<T, TAbi, TElementMarshaller>. + /// + /// The input element type. + /// The ABI type. + /// The element marshaller type. + public MethodSpecification IVectorMethodsManagedValueTypeGetMany(TypeSignature elementType, TypeSignature abiType, TypeSignature elementMarshallerType) + { + return IVectorMethodsManagedValueTypeExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + genericParameterCount: 3, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + new GenericParameterSignature(GenericParameterType.Method, 0).MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])) + .MakeGenericInstanceMethod([elementType, abiType, elementMarshallerType]); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsKeyValuePairTypeExtensions.GetMany<TKey, TValue, TElementMarshaller>. + /// + /// The input key type. + /// The input value type. + /// The element marshaller type. + public MethodSpecification IVectorMethodsKeyValuePairTypeGetMany(TypeSignature keyType, TypeSignature valueType, TypeSignature elementMarshallerType) + { + return IVectorMethodsKeyValuePairTypeExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + genericParameterCount: 3, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + KeyValuePair2.MakeGenericValueType([ + new GenericParameterSignature(GenericParameterType.Method, 0), + new GenericParameterSignature(GenericParameterType.Method, 1)]).MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])) + .MakeGenericInstanceMethod([keyType, valueType, elementMarshallerType]); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsNullableTypeExtensions.GetMany<T, TElementMarshaller>. + /// + /// The underlying value type. + /// The element marshaller type. + public MethodSpecification IVectorMethodsNullableTypeGetMany(TypeSignature underlyingType, TypeSignature elementMarshallerType) + { + return IVectorMethodsNullableTypeExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + genericParameterCount: 2, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + Nullable1.MakeGenericValueType([new GenericParameterSignature(GenericParameterType.Method, 0)]).MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])) + .MakeGenericInstanceMethod([underlyingType, elementMarshallerType]); + } + + /// + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsReferenceTypeExtensions.GetMany<T, TElementMarshaller>. + /// + /// The input element type. + /// The element marshaller type. + public MethodSpecification IVectorMethodsReferenceTypeGetMany(TypeSignature elementType, TypeSignature elementMarshallerType) + { + return IVectorMethodsReferenceTypeExtensions + .CreateMemberReference("GetMany"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Int32, + genericParameterCount: 2, + parameterTypes: [ + WindowsRuntimeObjectReference.ToReferenceTypeSignature(), + new GenericParameterSignature(GenericParameterType.Method, 0).MakeSzArrayType(), + _corLibTypeFactory.Int32, + _corLibTypeFactory.Int32])) + .MakeGenericInstanceMethod([elementType, elementMarshallerType]); + } + /// /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsImpl<T>.SetAt. /// @@ -6580,4 +6917,4 @@ public MemberReference ReadOnlyDictionaryValueCollection2_ctor(TypeSignature key new GenericParameterSignature(GenericParameterType.Type, 0), new GenericParameterSignature(GenericParameterType.Type, 1)])])]); } -} \ No newline at end of file +} diff --git a/src/WinRT.Runtime2/InteropServices/Collections/IListAdapterExtensions.cs b/src/WinRT.Runtime2/InteropServices/Collections/IListAdapterExtensions.cs index ddd8fe06d..46c90b1d3 100644 --- a/src/WinRT.Runtime2/InteropServices/Collections/IListAdapterExtensions.cs +++ b/src/WinRT.Runtime2/InteropServices/Collections/IListAdapterExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using WindowsRuntime.InteropServices.Marshalling; namespace WindowsRuntime.InteropServices; @@ -249,6 +250,22 @@ public static unsafe uint GetMany(IList list, uint startIndex, uint itemsSize int itemCount = int.Min((int)itemsSize, count - (int)startIndex); + Span destination = new(items, itemCount); + + if (list is T[] array) + { + array.AsSpan((int)startIndex, itemCount).CopyTo(destination); + + return (uint)itemCount; + } + + if (list is List concreteList) + { + CollectionsMarshal.AsSpan(concreteList).Slice((int)startIndex, itemCount).CopyTo(destination); + + return (uint)itemCount; + } + for (int i = 0; i < itemCount; i++) { items[i] = list[i + (int)startIndex]; diff --git a/src/WinRT.Runtime2/InteropServices/Collections/IListMethods{T}.cs b/src/WinRT.Runtime2/InteropServices/Collections/IListMethods{T}.cs index 849ecd40d..9ad4eb174 100644 --- a/src/WinRT.Runtime2/InteropServices/Collections/IListMethods{T}.cs +++ b/src/WinRT.Runtime2/InteropServices/Collections/IListMethods{T}.cs @@ -92,8 +92,17 @@ public static void CopyTo(WindowsRuntimeObjectReference thisReference, ArgumentException.ThrowInsufficientSpaceToCopyCollection(); } - // Copy all items into the target array, at the specified starting offset - for (int i = 0; i < count; i++) + // If there are no items to copy, we can just stop here + if (count == 0) + { + return; + } + + int copied = TMethods.GetMany(thisReference, array, arrayIndex, count); + + // Some vectors might return fewer items than requested, so preserve the semantics + // of 'ICollection.CopyTo' by retrieving any remaining items individually. + for (int i = copied; i < count; i++) { array[i + arrayIndex] = Item(thisReference, i); } diff --git a/src/WinRT.Runtime2/InteropServices/Collections/IVectorMethodsExtensions.cs b/src/WinRT.Runtime2/InteropServices/Collections/IVectorMethodsExtensions.cs new file mode 100644 index 000000000..f27f3c433 --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/Collections/IVectorMethodsExtensions.cs @@ -0,0 +1,513 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using WindowsRuntime.InteropServices.Marshalling; + +namespace WindowsRuntime.InteropServices; + +/// +/// Extensions for the type. +/// +[WindowsRuntimeImplementationOnlyMember] +public static unsafe class IVectorMethodsExtensions +{ + // Note: all the 'GetMany' extensions in this file share the same structure. Except for the blittable + // specialization, which can retrieve items straight into the target array, they retrieve the requested + // items from the native vector in batches, into a stack buffer, and then marshal each batch to managed. + // They can't be shared because each one needs a different ABI buffer type and marshalling logic, and + // sharing code for all of them would require some additional abstraction on top which would in turn + // increase overhead. To avoid that, we just keep a separate version of the code for each of them. Any + // changes to these methods should be kept in sync. + + /// + /// The maximum number of items to retrieve from a vector on each GetMany ABI call. + /// + internal const int GetManyBufferLength = 64; + + extension(IVectorMethods) + { + /// + /// Retrieves multiple items from the vector, starting from the first one, and copies them to a target array. + /// + /// The instance to use to invoke the native method. + /// The target array to copy the retrieved items to. + /// The zero-based index in to start copying to. + /// The number of items to retrieve from the vector. + /// The number of items that were retrieved. This value can be less than if the end of the vector is reached. + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, string[] array, int arrayIndex, int count) + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + HSTRING* items = stackalloc HSTRING[GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + try + { + // Marshal all retrieved items into the target array + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = HStringMarshaller.ConvertToManaged(items[i]); + } + } + finally + { + // Make sure to release all retrieved items, even if marshalling failed (this shouldn't ever throw) + for (int i = 0; i < actual; i++) + { + HStringMarshaller.Free(items[i]); + } + } + + copied += (int)actual; + + // If the vector returned fewer items than requested, we reached the end of the collection + if (actual < capacity) + { + break; + } + } + + return copied; + } + + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, object[] array, int arrayIndex, int count) + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + void** items = stackalloc void*[GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + try + { + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = WindowsRuntimeObjectMarshaller.ConvertToManaged(items[i])!; + } + } + finally + { + for (int i = 0; i < actual; i++) + { + WindowsRuntimeUnknownMarshaller.Free(items[i]); + } + } + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + + return copied; + } + + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, Exception[] array, int arrayIndex, int count) + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + ABI.System.Exception* items = stackalloc ABI.System.Exception[GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + // Exception values are just 'HRESULT'-s, so there's nothing to release after marshalling + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = ABI.System.ExceptionMarshaller.ConvertToManaged(items[i])!; + } + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + + return copied; + } + + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, Type[] array, int arrayIndex, int count) + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + ABI.System.Type* items = stackalloc ABI.System.Type[GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + try + { + // Same as with 'string' above, but with the 'Type' marshaller + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = ABI.System.TypeMarshaller.ConvertToManaged(items[i])!; + } + } + finally + { + // Make sure to dispose all retrieved values (this shouldn't ever throw) + for (int i = 0; i < actual; i++) + { + ABI.System.TypeMarshaller.Dispose(items[i]); + } + } + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + + return copied; + } + } +} + +/// +/// Extensions for the type for blittable value types. +/// +[WindowsRuntimeImplementationOnlyMember] +public static unsafe class IVectorMethodsBlittableValueTypeExtensions +{ + extension(IVectorMethods) + where T : unmanaged + { + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, T[] array, int arrayIndex, int count) + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + int copied = 0; + + // Blittable items don't need any marshalling, so we can retrieve them + // directly into the target array, with no intermediate stack buffer. + fixed (T* items = array) + { + while (copied < count) + { + uint capacity = (uint)(count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items + arrayIndex + copied, &actual)); + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + } + + return copied; + } + } +} + +/// +/// Extensions for the type for unmanaged value types. +/// +[WindowsRuntimeImplementationOnlyMember] +public static unsafe class IVectorMethodsUnmanagedValueTypeExtensions +{ + extension(IVectorMethods) + where T : unmanaged + where TAbi : unmanaged + { + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, T[] array, int arrayIndex, int count) + where TElementMarshaller : IWindowsRuntimeUnmanagedValueTypeElementMarshaller + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + TAbi* items = stackalloc TAbi[IVectorMethodsExtensions.GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(IVectorMethodsExtensions.GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + // Unmanaged value types have no resources to release after marshalling + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = TElementMarshaller.ConvertToManaged(items[i]); + } + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + + return copied; + } + } +} + +/// +/// Extensions for the type for managed value types. +/// +[WindowsRuntimeImplementationOnlyMember] +public static unsafe class IVectorMethodsManagedValueTypeExtensions +{ + extension(IVectorMethods) + where T : struct + where TAbi : unmanaged + { + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, T[] array, int arrayIndex, int count) + where TElementMarshaller : IWindowsRuntimeManagedValueTypeElementMarshaller + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + TAbi* items = stackalloc TAbi[IVectorMethodsExtensions.GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(IVectorMethodsExtensions.GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + try + { + // Same as with 'string' above, but with the provided marshaller + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = TElementMarshaller.ConvertToManaged(items[i]); + } + } + finally + { + // Make sure to dispose all retrieved values (this shouldn't ever throw) + for (int i = 0; i < actual; i++) + { + TElementMarshaller.Dispose(items[i]); + } + } + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + + return copied; + } + } +} + +/// +/// Extensions for the type for types. +/// +[WindowsRuntimeImplementationOnlyMember] +public static unsafe class IVectorMethodsKeyValuePairTypeExtensions +{ + extension(IVectorMethods) + { + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, KeyValuePair[] array, int arrayIndex, int count) + where TElementMarshaller : IWindowsRuntimeKeyValuePairTypeElementMarshaller + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + void** items = stackalloc void*[IVectorMethodsExtensions.GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(IVectorMethodsExtensions.GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + try + { + // Same as with 'string' above, but with the provided marshaller + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = TElementMarshaller.ConvertToManaged(items[i]); + } + } + finally + { + // Make sure to release all retrieved values (this shouldn't ever throw) + for (int i = 0; i < actual; i++) + { + TElementMarshaller.Dispose(items[i]); + } + } + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + + return copied; + } + } +} + +/// +/// Extensions for the type for types. +/// +[WindowsRuntimeImplementationOnlyMember] +public static unsafe class IVectorMethodsNullableTypeExtensions +{ + extension(IVectorMethods) + where T : struct + { + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, T?[] array, int arrayIndex, int count) + where TElementMarshaller : IWindowsRuntimeNullableTypeElementMarshaller + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + void** items = stackalloc void*[IVectorMethodsExtensions.GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(IVectorMethodsExtensions.GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + try + { + // Same as with 'string' above, but with the provided marshaller + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = TElementMarshaller.ConvertToManaged(items[i]); + } + } + finally + { + // Make sure to release all retrieved values (this shouldn't ever throw) + for (int i = 0; i < actual; i++) + { + TElementMarshaller.Dispose(items[i]); + } + } + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + + return copied; + } + } +} + +/// +/// Extensions for the type for reference types. +/// +[WindowsRuntimeImplementationOnlyMember] +public static unsafe class IVectorMethodsReferenceTypeExtensions +{ + extension(IVectorMethods) + where T : class + { + /// + public static int GetMany(WindowsRuntimeObjectReference thisReference, T[] array, int arrayIndex, int count) + where TElementMarshaller : IWindowsRuntimeReferenceTypeElementMarshaller + { + using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); + + void* thisPtr = thisValue.GetThisPtrUnsafe(); + void** items = stackalloc void*[IVectorMethodsExtensions.GetManyBufferLength]; + int copied = 0; + + while (copied < count) + { + uint capacity = (uint)int.Min(IVectorMethodsExtensions.GetManyBufferLength, count - copied); + uint actual; + + RestrictedErrorInfo.ThrowExceptionForHR(IVectorVftbl.GetManyUnsafe(thisPtr, (uint)copied, capacity, items, &actual)); + + try + { + for (int i = 0; i < actual; i++) + { + array[arrayIndex + copied + i] = TElementMarshaller.ConvertToManaged(items[i])!; + } + } + finally + { + for (int i = 0; i < actual; i++) + { + TElementMarshaller.Dispose(items[i]); + } + } + + copied += (int)actual; + + if (actual < capacity) + { + break; + } + } + + return copied; + } + } +} diff --git a/src/WinRT.Runtime2/InteropServices/Collections/IVectorMethodsImpl{T}.cs b/src/WinRT.Runtime2/InteropServices/Collections/IVectorMethodsImpl{T}.cs index bc240c276..adda808bb 100644 --- a/src/WinRT.Runtime2/InteropServices/Collections/IVectorMethodsImpl{T}.cs +++ b/src/WinRT.Runtime2/InteropServices/Collections/IVectorMethodsImpl{T}.cs @@ -19,6 +19,17 @@ public interface IVectorMethodsImpl /// static abstract T GetAt(WindowsRuntimeObjectReference thisReference, uint index); + /// + /// Retrieves multiple items from the vector, starting from the first one, and copies them to a target array. + /// + /// The instance to use to invoke the native method. + /// The target array to copy the retrieved items to. + /// The zero-based index in to start copying to. + /// The number of items to retrieve from the vector. + /// The number of items that were retrieved. This value can be less than if the end of the vector is reached. + /// + static abstract int GetMany(WindowsRuntimeObjectReference thisReference, T[] array, int arrayIndex, int count); + /// /// Sets the value at the specified index in the vector. /// diff --git a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeKeyValuePairTypeElementMarshaller{TKey, TValue}.cs b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeKeyValuePairTypeElementMarshaller{TKey, TValue}.cs index 56bd5f1b8..9268ccd13 100644 --- a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeKeyValuePairTypeElementMarshaller{TKey, TValue}.cs +++ b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeKeyValuePairTypeElementMarshaller{TKey, TValue}.cs @@ -6,12 +6,12 @@ namespace WindowsRuntime.InteropServices.Marshalling; /// -/// An interface for marshalling collection elements to native. +/// An interface for marshalling collection elements to and from native. /// /// The type of the key. /// The type of the value. [WindowsRuntimeImplementationOnlyMember] -public interface IWindowsRuntimeKeyValuePairTypeElementMarshaller +public unsafe interface IWindowsRuntimeKeyValuePairTypeElementMarshaller { /// /// Marshals a type to its native Windows Runtime representation. @@ -19,4 +19,17 @@ public interface IWindowsRuntimeKeyValuePairTypeElementMarshaller /// The input value to marshal. /// The marshalled native value. static abstract WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(KeyValuePair value); + + /// + /// Marshals a native Windows Runtime type to its managed representation. + /// + /// The input value to marshal. + /// The marshalled managed value. + static abstract KeyValuePair ConvertToManaged(void* value); + + /// + /// Disposes resources associated with an unmanaged value. + /// + /// The unmanaged value to dispose. + static abstract void Dispose(void* value); } diff --git a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeManagedValueTypeElementMarshaller{T, TAbi}.cs b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeManagedValueTypeElementMarshaller{T, TAbi}.cs index 827dc6e6f..b05dd3607 100644 --- a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeManagedValueTypeElementMarshaller{T, TAbi}.cs +++ b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeManagedValueTypeElementMarshaller{T, TAbi}.cs @@ -4,7 +4,7 @@ namespace WindowsRuntime.InteropServices.Marshalling; /// -/// An interface for marshalling collection elements to native. +/// An interface for marshalling collection elements to and from native. /// /// The type of elements in the array. /// The ABI type for type . @@ -20,6 +20,13 @@ public interface IWindowsRuntimeManagedValueTypeElementMarshaller /// The marshalled native value. static abstract TAbi ConvertToUnmanaged(T value); + /// + /// Marshals a native Windows Runtime value type to its managed representation. + /// + /// The input value to marshal. + /// The marshalled managed value. + static abstract T ConvertToManaged(TAbi value); + /// /// Disposes resources associated with an unmanaged value. /// diff --git a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeNullableTypeElementMarshaller{T}.cs b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeNullableTypeElementMarshaller{T}.cs index 7b8c2f794..1215d7590 100644 --- a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeNullableTypeElementMarshaller{T}.cs +++ b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeNullableTypeElementMarshaller{T}.cs @@ -6,11 +6,11 @@ namespace WindowsRuntime.InteropServices.Marshalling; /// -/// An interface for marshalling collection elements to native. +/// An interface for marshalling collection elements to and from native. /// /// The underlying value type of the nullable type. [WindowsRuntimeImplementationOnlyMember] -public interface IWindowsRuntimeNullableTypeElementMarshaller +public unsafe interface IWindowsRuntimeNullableTypeElementMarshaller where T : struct { /// @@ -19,4 +19,17 @@ public interface IWindowsRuntimeNullableTypeElementMarshaller /// The input value to marshal. /// The marshalled native value. static abstract WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(T? value); + + /// + /// Marshals a native Windows Runtime value to its managed representation. + /// + /// The input value to marshal. + /// The marshalled managed value. + static abstract T? ConvertToManaged(void* value); + + /// + /// Disposes resources associated with an unmanaged value. + /// + /// The unmanaged value to dispose. + static abstract void Dispose(void* value); } diff --git a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeReferenceTypeElementMarshaller{T}.cs b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeReferenceTypeElementMarshaller{T}.cs index d7516ed65..24d433b1a 100644 --- a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeReferenceTypeElementMarshaller{T}.cs +++ b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeReferenceTypeElementMarshaller{T}.cs @@ -4,11 +4,11 @@ namespace WindowsRuntime.InteropServices.Marshalling; /// -/// An interface for marshalling collection elements to native. +/// An interface for marshalling collection elements to and from native. /// /// The type of elements in the array. [WindowsRuntimeImplementationOnlyMember] -public interface IWindowsRuntimeReferenceTypeElementMarshaller +public unsafe interface IWindowsRuntimeReferenceTypeElementMarshaller where T : class { /// @@ -17,4 +17,17 @@ public interface IWindowsRuntimeReferenceTypeElementMarshaller /// The input object to marshal. /// A instance for . static abstract WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(T? value); + + /// + /// Converts an unmanaged pointer to a Windows Runtime object to a managed object. + /// + /// The input object to convert to managed. + /// The resulting managed object. + static abstract T? ConvertToManaged(void* value); + + /// + /// Disposes resources associated with an unmanaged value. + /// + /// The unmanaged value to dispose. + static abstract void Dispose(void* value); } diff --git a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeUnmanagedValueTypeElementMarshaller{T, TAbi}.cs b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeUnmanagedValueTypeElementMarshaller{T, TAbi}.cs index bfb03fcb8..8f657754d 100644 --- a/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeUnmanagedValueTypeElementMarshaller{T, TAbi}.cs +++ b/src/WinRT.Runtime2/InteropServices/Marshalling/Collections/IWindowsRuntimeUnmanagedValueTypeElementMarshaller{T, TAbi}.cs @@ -4,7 +4,7 @@ namespace WindowsRuntime.InteropServices.Marshalling; /// -/// An interface for marshalling collection elements to native. +/// An interface for marshalling collection elements to and from native. /// /// The type of elements in the array. /// The ABI type for type . @@ -19,4 +19,11 @@ public interface IWindowsRuntimeUnmanagedValueTypeElementMarshaller /// The input value to marshal. /// The marshalled native value. static abstract TAbi ConvertToUnmanaged(T value); + + /// + /// Marshals a native Windows Runtime value type to its managed representation. + /// + /// The input value to marshal. + /// The marshalled managed value. + static abstract T ConvertToManaged(TAbi value); } diff --git a/src/WinRT.Runtime2/InteropServices/Vtables/IVectorVftbl.cs b/src/WinRT.Runtime2/InteropServices/Vtables/IVectorVftbl.cs index 303cabe49..76fb698d3 100644 --- a/src/WinRT.Runtime2/InteropServices/Vtables/IVectorVftbl.cs +++ b/src/WinRT.Runtime2/InteropServices/Vtables/IVectorVftbl.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Windows.Foundation; @@ -34,4 +35,19 @@ internal unsafe struct IVectorVftbl public delegate* unmanaged[MemberFunction] Clear; public delegate* unmanaged[MemberFunction] GetMany; public delegate* unmanaged[MemberFunction] ReplaceAll; + + /// + /// Retrieves multiple items from the vector beginning at the given index. + /// + /// The target COM object. + /// The zero-based index of the first item to retrieve. + /// The number of items that can be written to . + /// The target buffer to write the retrieved items to. + /// The number of items that were retrieved. + /// The HRESULT for the operation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HRESULT GetManyUnsafe(void* thisPtr, uint startIndex, uint capacity, void* items, uint* actual) + { + return ((IVectorVftbl*)*(void***)thisPtr)->GetMany(thisPtr, startIndex, capacity, items, actual); + } } \ No newline at end of file