From 14977e38fc259d4c4aa0c16ebf41b8d84741a95d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 14:44:50 -0800 Subject: [PATCH 01/31] Add IID for IMapChangedEventArgs1 interface Added a new case to return the IID for the IMapChangedEventArgs1 interface in WellKnownInterfaceIIDs. This supports recognition of the interface in interop scenarios. --- .../References/WellKnownInterfaceIIDs.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs b/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs index e95112ff3..41745f641 100644 --- a/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs +++ b/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs @@ -192,6 +192,8 @@ _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.V => new Guid("A1E9ACD7-E4DF-5A79-AEFA-DE07934AB0FB"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.AsyncActionProgressHandler1) => new Guid("C261D8D0-71BA-5F38-A239-872342253A18"), + _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IMapChangedEventArgs1) + => new Guid("9939F4DF-050A-4C0F-AA60-77075F9C4777"), _ when SignatureComparer.IgnoreVersion.Equals(interfaceType, interopReferences.IVectorChangedEventArgs) => new Guid("575933DF-34FE-4480-AF15-07691F3D5D9B"), From 43fa9c3b6d8972300cc0452153e994e9b98538d1 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 15:03:49 -0800 Subject: [PATCH 02/31] Refactor delegate invoke method body construction Simplifies and restructures the construction of the delegate 'Invoke' method body by reducing local variables, consolidating instruction setup, and streamlining exception handling. This refactor improves readability and maintainability of the interop delegate generation logic. --- .../InteropTypeDefinitionBuilder.Delegate.cs | 151 +++++++----------- 1 file changed, 62 insertions(+), 89 deletions(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index 0b1b74009..bc53d7d17 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -436,15 +436,10 @@ public static void NativeDelegateType( parameterTypes: [ interopReferences.WindowsRuntimeObjectReference.ToReferenceTypeSignature().Import(module), senderType.Import(module), - argsType.Import(module)])) - { CilMethodBody = new CilMethodBody() }; + argsType.Import(module)])); nativeDelegateType.Methods.Add(invokeMethod); - // Get the method body for the 'Invoke' method - CilMethodBody invokeBody = invokeMethod.CilMethodBody; - CilInstructionCollection invokeInstructions = invokeBody.Instructions; - // Import 'WindowsRuntimeObjectReferenceValue', compute it just once TypeSignature windowsRuntimeObjectReferenceValueType = interopReferences.WindowsRuntimeObjectReferenceValue .Import(module) @@ -452,93 +447,71 @@ public static void NativeDelegateType( // Declare the local variables: // [0]: 'WindowsRuntimeObjectReferenceValue' (for 'thisValue') - // [1]: 'WindowsRuntimeObjectReferenceValue' (for 'senderValue') - // [2]: 'WindowsRuntimeObjectReferenceValue' (for 'eValue') - // [3]: 'void*' (for 'thisPtr') - invokeBody.LocalVariables.Add(new CilLocalVariable(windowsRuntimeObjectReferenceValueType)); - invokeBody.LocalVariables.Add(new CilLocalVariable(windowsRuntimeObjectReferenceValueType)); - invokeBody.LocalVariables.Add(new CilLocalVariable(windowsRuntimeObjectReferenceValueType)); - invokeBody.LocalVariables.Add(new CilLocalVariable(module.CorLibTypeFactory.Void.MakePointerType())); + // [1]: 'void*' (for 'thisPtr') + CilLocalVariable loc_0_thisValue = new(windowsRuntimeObjectReferenceValueType); + CilLocalVariable loc_1_thisPtr = new(module.CorLibTypeFactory.Void.MakePointerType()); + // Jump labels + CilInstruction nop_try_0 = new(Nop); + CilInstruction nop_try_1 = new(Nop); + CilInstruction nop_ld_sender = new(Nop); + CilInstruction nop_ld_args = new(Nop); + CilInstruction ldloca_0_invoke = new(Ldloca_S, loc_0_thisValue); + CilInstruction ldloca_0_finally_0 = new(Ldloca_S, loc_0_thisValue); CilInstruction ret = new(Ret); - // Load the local [0] - _ = invokeInstructions.Add(Ldarg_0); - _ = invokeInstructions.Add(Callvirt, interopReferences.WindowsRuntimeObjectReferenceAsValue.Import(module)); - _ = invokeInstructions.Add(Stloc_0); - - // '.try' for local [0] - CilInstruction try_0 = invokeInstructions.Add(Ldarg_1); - _ = invokeInstructions.Add(Call, interopReferences.WindowsRuntimeObjectMarshallerConvertToUnmanaged.Import(module)); - _ = invokeInstructions.Add(Stloc_1); - - // '.try' for local [1] - CilInstruction try_1 = invokeInstructions.Add(Ldarg_2); - _ = invokeInstructions.Add(Call, interopReferences.WindowsRuntimeObjectMarshallerConvertToUnmanaged.Import(module)); - _ = invokeInstructions.Add(Stloc_2); - - // 'Invoke' call for the native delegate (and 'try' for local [2]) - CilInstruction try_2 = invokeInstructions.Add(Ldloca_S, invokeBody.LocalVariables[0]); - _ = invokeInstructions.Add(Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module)); - _ = invokeInstructions.Add(Stloc_3); - _ = invokeInstructions.Add(Ldloc_3); - _ = invokeInstructions.Add(Ldloca_S, invokeBody.LocalVariables[1]); - _ = invokeInstructions.Add(Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module)); - _ = invokeInstructions.Add(Ldloca_S, invokeBody.LocalVariables[2]); - _ = invokeInstructions.Add(Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module)); - _ = invokeInstructions.Add(Ldloc_3); - _ = invokeInstructions.Add(Ldind_I); - _ = invokeInstructions.Add(Ldfld, interopDefinitions.DelegateVftbl.Fields[3]); - _ = invokeInstructions.Add(Calli, WellKnownTypeSignatureFactory.InvokeImpl(interopReferences).Import(module).MakeStandAloneSignature()); - _ = invokeInstructions.Add(Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module)); - _ = invokeInstructions.Add(Leave_S, ret.CreateLabel()); - - // 'finally' for local [2] - CilInstruction finally_2 = invokeInstructions.Add(Ldloca_S, invokeBody.LocalVariables[2]); - _ = invokeInstructions.Add(Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module)); - _ = invokeInstructions.Add(Endfinally); - - // 'finally' for local [1] - CilInstruction finally_1 = invokeInstructions.Add(Ldloca_S, invokeBody.LocalVariables[1]); - _ = invokeInstructions.Add(Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module)); - _ = invokeInstructions.Add(Endfinally); - - // 'finally' for local [0] - CilInstruction finally_0 = invokeInstructions.Add(Ldloca_S, invokeBody.LocalVariables[0]); - _ = invokeInstructions.Add(Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module)); - _ = invokeInstructions.Add(Endfinally); - - invokeInstructions.Add(ret); - - // Setup 'try/finally' for local [0] - invokeBody.ExceptionHandlers.Add(new CilExceptionHandler - { - HandlerType = CilExceptionHandlerType.Finally, - TryStart = try_0.CreateLabel(), - TryEnd = finally_0.CreateLabel(), - HandlerStart = finally_0.CreateLabel(), - HandlerEnd = ret.CreateLabel() - }); - - // Setup 'try/finally' for local [1] - invokeBody.ExceptionHandlers.Add(new CilExceptionHandler - { - HandlerType = CilExceptionHandlerType.Finally, - TryStart = try_1.CreateLabel(), - TryEnd = finally_1.CreateLabel(), - HandlerStart = finally_1.CreateLabel(), - HandlerEnd = finally_0.CreateLabel() - }); - - // Setup 'try/finally' for local [2] - invokeBody.ExceptionHandlers.Add(new CilExceptionHandler + // Create a method body for the 'Invoke' method + invokeMethod.CilMethodBody = new CilMethodBody() { - HandlerType = CilExceptionHandlerType.Finally, - TryStart = try_2.CreateLabel(), - TryEnd = finally_2.CreateLabel(), - HandlerStart = finally_2.CreateLabel(), - HandlerEnd = finally_1.CreateLabel() - }); + LocalVariables = { loc_0_thisValue, loc_1_thisPtr }, + Instructions = + { + // Load the local [0] + { Ldarg_0 }, + { Callvirt, interopReferences.WindowsRuntimeObjectReferenceAsValue.Import(module) }, + { Stloc_0 }, + + // Arguments loading inside outer 'try/catch' block + { nop_try_0 }, + { nop_try_1 }, + + // 'Invoke' call for the native delegate (and 'try' for local [2]) + { ldloca_0_invoke }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module) }, + { Stloc_1 }, + { Ldloc_1 }, + { nop_ld_sender }, + { nop_ld_args }, + { Ldnull }, // TODO: remove + { Ldnull }, // TODO: remove + { Ldloc_1 }, + { Ldind_I }, + { Ldfld, interopDefinitions.DelegateVftbl.Fields[3] }, + { Calli, WellKnownTypeSignatureFactory.InvokeImpl(interopReferences).Import(module).MakeStandAloneSignature() }, + { Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module) }, + { Leave_S, ret.CreateLabel() }, + + // 'finally' for local [0] + { ldloca_0_finally_0 }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module) }, + { Endfinally }, + + // return; + { ret } + }, + ExceptionHandlers = + { + // Setup 'try/finally' for local [0] + new CilExceptionHandler + { + HandlerType = CilExceptionHandlerType.Finally, + TryStart = nop_try_0.CreateLabel(), + TryEnd = ldloca_0_finally_0.CreateLabel(), + HandlerStart = ldloca_0_finally_0.CreateLabel(), + HandlerEnd = ret.CreateLabel() + } + } + }; } /// From 9143aac5b0d3cbc775b8e2cde338d14a8f41a6c5 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 15:19:51 -0800 Subject: [PATCH 03/31] Refactor delegate exception handling labels Renamed and added jump labels for try and finally blocks in delegate generation to improve clarity and support parameter-specific cleanup. Updated exception handler to use new label names. --- .../InteropTypeDefinitionBuilder.Delegate.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index bc53d7d17..10c3daad9 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -452,10 +452,13 @@ public static void NativeDelegateType( CilLocalVariable loc_1_thisPtr = new(module.CorLibTypeFactory.Void.MakePointerType()); // Jump labels - CilInstruction nop_try_0 = new(Nop); - CilInstruction nop_try_1 = new(Nop); + CilInstruction nop_try_this = new(Nop); + CilInstruction nop_try_sender = new(Nop); + CilInstruction nop_try_args = new(Nop); CilInstruction nop_ld_sender = new(Nop); CilInstruction nop_ld_args = new(Nop); + CilInstruction nop_finally_sender = new(Nop); + CilInstruction nop_finally_args = new(Nop); CilInstruction ldloca_0_invoke = new(Ldloca_S, loc_0_thisValue); CilInstruction ldloca_0_finally_0 = new(Ldloca_S, loc_0_thisValue); CilInstruction ret = new(Ret); @@ -470,10 +473,11 @@ public static void NativeDelegateType( { Ldarg_0 }, { Callvirt, interopReferences.WindowsRuntimeObjectReferenceAsValue.Import(module) }, { Stloc_0 }, + { nop_try_this }, // Arguments loading inside outer 'try/catch' block - { nop_try_0 }, - { nop_try_1 }, + { nop_try_sender }, + { nop_try_args }, // 'Invoke' call for the native delegate (and 'try' for local [2]) { ldloca_0_invoke }, @@ -491,6 +495,11 @@ public static void NativeDelegateType( { Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module) }, { Leave_S, ret.CreateLabel() }, + // Optional 'finally' blocks for the marshalled parameters. These are intentionally + // in reverse order, as the inner-most parameter should be released first. + { nop_finally_args }, + { nop_finally_sender }, + // 'finally' for local [0] { ldloca_0_finally_0 }, { Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module) }, @@ -505,7 +514,7 @@ public static void NativeDelegateType( new CilExceptionHandler { HandlerType = CilExceptionHandlerType.Finally, - TryStart = nop_try_0.CreateLabel(), + TryStart = nop_try_this.CreateLabel(), TryEnd = ldloca_0_finally_0.CreateLabel(), HandlerStart = ldloca_0_finally_0.CreateLabel(), HandlerEnd = ret.CreateLabel() From 419a6add40b3bd6b4b43de91a4cae1fe02469040 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 15:34:53 -0800 Subject: [PATCH 04/31] Inline ldloca_0_invoke instruction in delegate builder Replaces the ldloca_0_invoke variable with an inlined instruction in the InteropTypeDefinitionBuilder.Delegate code, simplifying the instruction list and improving code clarity. --- .../Builders/InteropTypeDefinitionBuilder.Delegate.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index 10c3daad9..e491c0345 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -459,7 +459,6 @@ public static void NativeDelegateType( CilInstruction nop_ld_args = new(Nop); CilInstruction nop_finally_sender = new(Nop); CilInstruction nop_finally_args = new(Nop); - CilInstruction ldloca_0_invoke = new(Ldloca_S, loc_0_thisValue); CilInstruction ldloca_0_finally_0 = new(Ldloca_S, loc_0_thisValue); CilInstruction ret = new(Ret); @@ -480,7 +479,7 @@ public static void NativeDelegateType( { nop_try_args }, // 'Invoke' call for the native delegate (and 'try' for local [2]) - { ldloca_0_invoke }, + { Ldloca_S, loc_0_thisValue }, { Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module) }, { Stloc_1 }, { Ldloc_1 }, From e4fde7e0aa5f404a5c518b7ea3a6aba833a77ce6 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 15:59:40 -0800 Subject: [PATCH 05/31] Add NativeParameter marshalling logic to Interop factory Introduces the NativeParameter class to InteropMethodRewriteFactory, providing initial structure and validation for marshalling native parameters in method rewrites. Includes parameter type checks, marker validation, and basic handling for blittable value types, with placeholders for additional type cases. --- ...opMethodRewriteFactory.ManagedParameter.cs | 3 +- ...ropMethodRewriteFactory.NativeParameter.cs | 111 ++++++++++++++++++ 2 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs index bae3eec7e..e8114a61c 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs @@ -52,8 +52,7 @@ public static void RewriteMethod( throw WellKnownInteropExceptions.MethodRewriteMarkerInstructionNotFoundError(marker, method); } - // If we didn't find the marker, it means the target method is either invalid, or the - // supplied marker was incorrect (or the caller forgot to add it to the method body). + // Validate that the target parameter index is in range if ((uint)parameterIndex >= method.Parameters.Count) { throw WellKnownInteropExceptions.MethodRewriteParameterIndexNotValidError(parameterIndex, method); diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs new file mode 100644 index 000000000..8fd4061f6 --- /dev/null +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using AsmResolver.DotNet; +using AsmResolver.DotNet.Code.Cil; +using AsmResolver.DotNet.Collections; +using AsmResolver.DotNet.Signatures; +using AsmResolver.PE.DotNet.Cil; +using WindowsRuntime.InteropGenerator.Errors; +using WindowsRuntime.InteropGenerator.Generation; +using WindowsRuntime.InteropGenerator.References; + +namespace WindowsRuntime.InteropGenerator.Factories; + +/// +internal partial class InteropMethodRewriteFactory +{ + /// + /// Contains the logic for marshalling native parameters (i.e. parameters that are passed to native methods). + /// + public static class NativeParameter + { + /// + /// Performs two-pass code generation on a target method to marshal a managed parameter. + /// + /// The parameter type that needs to be marshalled. + /// The target method to perform two-pass code generation on. + /// The target IL instruction to replace with the right set of specialized instructions, for the optional block. + /// The target IL instruction to replace with the right set of specialized instructions to load the marshalled value. + /// The target IL instruction to replace with the right set of specialized instructions, for the optional block. + /// The index of the parameter to marshal. + /// The instance to use. + /// The emit state for this invocation. + /// The interop module being built. + public static void RewriteMethod( + TypeSignature parameterType, + MethodDefinition method, + CilInstruction tryMarker, + CilInstruction loadMarker, + CilInstruction finallyMarker, + int parameterIndex, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState, + ModuleDefinition module) + { + // Validate that we do have some IL body for the input method (this should always be the case) + if (method.CilMethodBody is not CilMethodBody body) + { + throw WellKnownInteropExceptions.MethodRewriteMissingBodyError(method); + } + + // If we didn't find any of markers, it means the target method is either invalid + foreach (CilInstruction marker in (ReadOnlySpan)[tryMarker, loadMarker, finallyMarker]) + { + if (!body.Instructions.Contains(marker)) + { + throw WellKnownInteropExceptions.MethodRewriteMarkerInstructionNotFoundError(marker, method); + } + } + + // Validate that the target parameter index is in range + if ((uint)parameterIndex >= method.Parameters.Count) + { + throw WellKnownInteropExceptions.MethodRewriteParameterIndexNotValidError(parameterIndex, method); + } + + Parameter source = method.Parameters[parameterIndex]; + + // Validate that the type matches + if (!SignatureComparer.IgnoreVersion.Equals(source.ParameterType, parameterType)) + { + throw WellKnownInteropExceptions.MethodRewriteSourceParameterTypeMismatchError(source.ParameterType, parameterType, method); + } + + if (parameterType.IsValueType) + { + // If the return type is blittable, we can just load it directly it directly (simplest case) + if (parameterType.IsBlittable(interopReferences)) + { + body.Instructions.RemoveRange([tryMarker, finallyMarker]); + body.Instructions.ReplaceRange(loadMarker, CilInstruction.CreateLdarg(parameterIndex)); + } + else if (parameterType.IsConstructedKeyValuePairType(interopReferences)) + { + // TODO + } + else if (parameterType.IsConstructedNullableValueType(interopReferences)) + { + // TODO + } + else + { + // TODO + } + } + else if (parameterType.IsTypeOfString()) + { + // TODO + } + else if (parameterType is GenericInstanceTypeSignature) + { + // TODO + } + else + { + // TODO + } + } + } +} \ No newline at end of file From eb9d32be1672f8455c4c0093f2cc5c46be7af99f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 19:03:32 -0800 Subject: [PATCH 06/31] Handle Exception type marshalling in native parameter rewrite Added logic to directly marshal Exception parameters as unmanaged types in InteropMethodRewriteFactory.NativeParameter. This includes removing try/finally markers and inserting instructions to convert Exception to its unmanaged representation using the ExceptionMarshaller. --- .../InteropMethodRewriteFactory.NativeParameter.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs index 8fd4061f6..0dc1246f5 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs @@ -10,6 +10,7 @@ using WindowsRuntime.InteropGenerator.Errors; using WindowsRuntime.InteropGenerator.Generation; using WindowsRuntime.InteropGenerator.References; +using static AsmResolver.PE.DotNet.Cil.CilOpCodes; namespace WindowsRuntime.InteropGenerator.Factories; @@ -98,6 +99,18 @@ public static void RewriteMethod( { // TODO } + else if (parameterType.IsTypeOfType(interopReferences)) + { + + } + else if (parameterType.IsTypeOfException(interopReferences)) + { + // The ABI type of 'Exception' is unmanaged, so we can marshal the value directly + body.Instructions.RemoveRange([tryMarker, finallyMarker]); + body.Instructions.ReplaceRange(loadMarker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, interopReferences.ExceptionMarshallerConvertToUnmanaged.Import(module))]); + } else if (parameterType is GenericInstanceTypeSignature) { // TODO From a73424cd06a0daa23bc8fb47ce54cac742f0312f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:13:55 -0800 Subject: [PATCH 07/31] Add IsTypeOfVoidPointer method to WindowsRuntimeExtensions Introduces a new method to check if an ITypeDescriptor is a void pointer type, improving type analysis capabilities in WindowsRuntimeExtensions. --- .../Extensions/WindowsRuntimeExtensions.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs index 791bc3859..07d7f65d5 100644 --- a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs @@ -92,6 +92,15 @@ public bool IsTypeOfObject() return type is CorLibTypeSignature { ElementType: ElementType.Object }; } + /// + /// Checks whether an is a pointer type. + /// + /// Whether the type is a pointer type. + public bool IsTypeOfVoidPointer() + { + return type is PointerTypeSignature { BaseType: CorLibTypeSignature { ElementType: ElementType.Void } }; + } + /// /// Checks whether an represents a fundamental Windows Runtime type. /// From 58f4a1878c9f99e4dc83f5660eb2441e62e310c9 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:14:01 -0800 Subject: [PATCH 08/31] Implement marshalling logic for native parameters Adds marshalling and disposal logic for various parameter types in InteropMethodRewriteFactory.NativeParameter, including constructed key-value pairs, nullable value types, strings, types, exceptions, and other value/reference types. Introduces the RewriteBody helper to handle marshalling and cleanup, improving support for complex parameter scenarios in interop method rewriting. --- ...ropMethodRewriteFactory.NativeParameter.cs | 182 +++++++++++++++++- 1 file changed, 175 insertions(+), 7 deletions(-) diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs index 0dc1246f5..98b17b330 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs @@ -12,6 +12,8 @@ using WindowsRuntime.InteropGenerator.References; using static AsmResolver.PE.DotNet.Cil.CilOpCodes; +#pragma warning disable CS1573 + namespace WindowsRuntime.InteropGenerator.Factories; /// @@ -84,24 +86,87 @@ public static void RewriteMethod( } else if (parameterType.IsConstructedKeyValuePairType(interopReferences)) { - // TODO + RewriteBody( + parameterType: parameterType, + body: body, + tryMarker: tryMarker, + loadMarker: loadMarker, + finallyMarker: finallyMarker, + parameterIndex: parameterIndex, + marshallerMethod: emitState.LookupTypeDefinition(parameterType, "Marshaller").GetMethod("ConvertToUnmanaged"), + disposeMethod: null, + interopReferences: interopReferences, + module: module); } else if (parameterType.IsConstructedNullableValueType(interopReferences)) { - // TODO + TypeSignature underlyingType = ((GenericInstanceTypeSignature)parameterType).TypeArguments[0]; + + // For 'Nullable' return types, we need the marshaller for the instantiated 'T' type (same as for return values) + ITypeDefOrRef marshallerType = GetValueTypeMarshallerType(underlyingType, interopReferences, emitState); + + // Get the right reference to the unboxing marshalling method to call + IMethodDefOrRef marshallerMethod = marshallerType.GetMethodDefOrRef( + name: "BoxToUnmanaged"u8, + signature: MethodSignature.CreateStatic( + returnType: interopReferences.WindowsRuntimeObjectReferenceValue.ToValueTypeSignature(), + parameterTypes: [parameterType])); + + RewriteBody( + parameterType: parameterType, + body: body, + tryMarker: tryMarker, + loadMarker: loadMarker, + finallyMarker: finallyMarker, + parameterIndex: parameterIndex, + marshallerMethod: marshallerMethod, + disposeMethod: null, + interopReferences: interopReferences, + module: module); } else { - // TODO + // The last case handles all other value types, which need explicit disposal for their ABI values + ITypeDefOrRef marshallerType = GetValueTypeMarshallerType(parameterType, interopReferences, emitState); + + // Get the reference to 'ConvertToUnmanaged' to produce the resulting value to pass as argument + IMethodDefOrRef marshallerMethod = marshallerType.GetMethodDefOrRef( + name: "ConvertToUnmanaged"u8, + signature: MethodSignature.CreateStatic( + returnType: parameterType.GetAbiType(interopReferences), + parameterTypes: [parameterType])); + + // Get the reference to 'Dispose' method to call on the ABI value + IMethodDefOrRef disposeMethod = marshallerType.GetMethodDefOrRef( + name: "Dispose"u8, + signature: MethodSignature.CreateStatic( + returnType: interopReferences.CorLibTypeFactory.Void, + parameterTypes: [parameterType.GetAbiType(interopReferences)])); + + RewriteBody( + parameterType: parameterType, + body: body, + tryMarker: tryMarker, + loadMarker: loadMarker, + finallyMarker: finallyMarker, + parameterIndex: parameterIndex, + marshallerMethod: marshallerMethod, + disposeMethod: disposeMethod, + interopReferences: interopReferences, + module: module); } } else if (parameterType.IsTypeOfString()) { // TODO + body.Instructions.RemoveRange([tryMarker, finallyMarker]); + body.Instructions.ReplaceRange(loadMarker, new CilInstruction(Ldnull)); } else if (parameterType.IsTypeOfType(interopReferences)) { - + // TODO + body.Instructions.RemoveRange([tryMarker, finallyMarker]); + body.Instructions.ReplaceRange(loadMarker, new CilInstruction(Ldnull)); } else if (parameterType.IsTypeOfException(interopReferences)) { @@ -111,14 +176,117 @@ public static void RewriteMethod( CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, interopReferences.ExceptionMarshallerConvertToUnmanaged.Import(module))]); } - else if (parameterType is GenericInstanceTypeSignature) + else { - // TODO + // Get the marshaller for all other types (doesn't matter if constructed generics or not) + ITypeDefOrRef marshallerType = GetReferenceTypeMarshallerType(parameterType, interopReferences, emitState); + + // Get the reference to 'ConvertToUnmanaged' to produce the resulting value to pass as argument + IMethodDefOrRef marshallerMethod = marshallerType.GetMethodDefOrRef( + name: "ConvertToUnmanaged"u8, + signature: MethodSignature.CreateStatic( + returnType: interopReferences.WindowsRuntimeObjectReferenceValue.ToValueTypeSignature(), + parameterTypes: [parameterType])); + + RewriteBody( + parameterType: parameterType, + body: body, + tryMarker: tryMarker, + loadMarker: loadMarker, + finallyMarker: finallyMarker, + parameterIndex: parameterIndex, + marshallerMethod: marshallerMethod, + disposeMethod: null, + interopReferences: interopReferences, + module: module); + } + } + + /// + /// The target body to perform two-pass code generation on. + /// The method to invoke to marshal the managed value. + /// The method to invoke to dispose the original ABI value, if a value type. + private static void RewriteBody( + TypeSignature parameterType, + CilMethodBody body, + CilInstruction tryMarker, + CilInstruction loadMarker, + CilInstruction finallyMarker, + int parameterIndex, + IMethodDefOrRef marshallerMethod, + IMethodDefOrRef? disposeMethod, + InteropReferences interopReferences, + ModuleDefinition module) + { + TypeSignature parameterAbiType = parameterType.GetAbiType(interopReferences); + + // Prepare the new local for the ABI value (or 'WindowsRuntimeObjectReferenceValue'). + // This is only for parameter types that need some kind of disposal after the call. + CilLocalVariable loc_parameter = parameterAbiType.IsTypeOfVoidPointer() + ? new CilLocalVariable(interopReferences.WindowsRuntimeObjectReferenceValue.Import(module).ToValueTypeSignature()) + : new CilLocalVariable(parameterAbiType.Import(module)); + + body.LocalVariables.Add(loc_parameter); + + // Prepare the jump labels + CilInstruction nop_tryStart = new(Nop); + CilInstruction ldloc_or_a_finallyStart; + CilInstruction nop_finallyEnd = new(Nop); + + // Marshal the value before the call + body.Instructions.ReplaceRange(tryMarker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Call, marshallerMethod.Import(module)), + CilInstruction.CreateStloc(loc_parameter, body), + nop_tryStart]); + + // Get the ABI value to pass to the native method. If we have a 'WindowsRuntimeObjectReferenceValue', + // we'll get the pointer from it. Otherwise, we just load the ABI value and pass it directly to native. + if (parameterAbiType.IsTypeOfVoidPointer()) + { + body.Instructions.ReplaceRange(loadMarker, [ + new CilInstruction(Ldloca_S, loc_parameter), + new CilInstruction(Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module))]); } else { - // TODO + body.Instructions.ReplaceRange(loadMarker, CilInstruction.CreateLdloc(loc_parameter, body)); + } + + // Release the ABI value, or the 'WindowsRuntimeObjectReferenceValue' value, after the call. + // Once again we need specialized logic for when we're using 'WindowsRuntimeObjectReferenceValue'. + // That is, for that object we'll need to call the instance 'Dispose' on it directly. For all + // other cases, we'll instead load the local and pass it to the 'Dispose' method on the marshaller. + if (parameterAbiType.IsTypeOfVoidPointer()) + { + ldloc_or_a_finallyStart = new CilInstruction(Ldloca_S, loc_parameter); + + body.Instructions.ReplaceRange(finallyMarker, [ + ldloc_or_a_finallyStart, + new CilInstruction(Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module)), + new CilInstruction(Endfinally), + nop_finallyEnd]); } + else + { + ldloc_or_a_finallyStart = CilInstruction.CreateLdloc(loc_parameter, body); + + body.Instructions.ReplaceRange(finallyMarker, [ + ldloc_or_a_finallyStart, + new CilInstruction(Call, disposeMethod!.Import(module)), + new CilInstruction(Endfinally), + nop_finallyEnd]); + } + + // Setup the protected region to call the 'Dispose' method in a 'finally' block + body.ExceptionHandlers.Add(new CilExceptionHandler + { + HandlerType = CilExceptionHandlerType.Finally, + TryStart = nop_tryStart.CreateLabel(), + TryEnd = ldloc_or_a_finallyStart.CreateLabel(), + HandlerStart = ldloc_or_a_finallyStart.CreateLabel(), + HandlerEnd = nop_finallyEnd.CreateLabel() + }); } } } \ No newline at end of file From f62370a1bf07f939d4f275acfb594e4850a90c81 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:21:09 -0800 Subject: [PATCH 09/31] Add NativeParameter class for method rewrite info Introduces the NativeParameter class to MethodRewriteInfo for handling native parameters in two-pass IL generation. Also updates ManagedParameter XML documentation to reference the correct factory method. --- .../MethodRewriteInfo.ManagedParameter.cs | 2 +- .../MethodRewriteInfo.NativeParameter.cs | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.NativeParameter.cs diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs index 5e18a8788..769ff45ac 100644 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs @@ -9,7 +9,7 @@ internal partial class MethodRewriteInfo /// /// Contains info for a target method for two-pass IL generation, for a managed parameter. /// - /// + /// public sealed class ManagedParameter : MethodRewriteInfo { /// diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.NativeParameter.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.NativeParameter.cs new file mode 100644 index 000000000..49b2a1ba9 --- /dev/null +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.NativeParameter.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using AsmResolver.PE.DotNet.Cil; + +namespace WindowsRuntime.InteropGenerator.Models; + +/// +internal partial class MethodRewriteInfo +{ + /// + /// Contains info for a target method for two-pass IL generation, for a native parameter. + /// + /// + public sealed class NativeParameter : MethodRewriteInfo + { + /// + public required CilInstruction TryMarker { get; init; } + + /// + public required CilInstruction FinallyMarker { get; init; } + + /// + public required int ParameterIndex { get; init; } + + /// + public override int CompareTo(MethodRewriteInfo? other) + { + if (other is null) + { + return 1; + } + + if (ReferenceEquals(this, other)) + { + return 0; + } + + // If the input object is of a different type, just sort alphabetically based on the type name + if (other is not NativeParameter info) + { + return typeof(NativeParameter).FullName!.CompareTo(other.GetType().FullName!); + } + + int result = CompareByMethodRewriteInfo(other); + + // If the two items are already not equal, we can stop here + if (result != 0) + { + return result; + } + + int leftIndex = Method.CilMethodBody?.Instructions.IndexOf(TryMarker) ?? -1; + int rightIndex = other.Method.CilMethodBody?.Instructions.IndexOf(info.TryMarker) ?? -1; + + result = leftIndex.CompareTo(rightIndex); + + // Compare by the position of the marker for the 'try' block + if (result != 0) + { + return result; + } + + leftIndex = Method.CilMethodBody?.Instructions.IndexOf(FinallyMarker) ?? -1; + rightIndex = other.Method.CilMethodBody?.Instructions.IndexOf(info.FinallyMarker) ?? -1; + + result = leftIndex.CompareTo(rightIndex); + + // Next, compare by the position of the marker for the 'finally' block + if (result != 0) + { + return result; + } + + // Lastly, compare by parameter index + return ParameterIndex.CompareTo(info.ParameterIndex); + } + } +} From d7ae2e9e181dcd25ae3df031d7fd01e495d363aa Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:22:58 -0800 Subject: [PATCH 10/31] Add support for native parameter method rewrite Introduces handling for MethodRewriteInfo.NativeParameter in the method rewrite switch, enabling native parameter rewriting via InteropMethodRewriteFactory.NativeParameter.RewriteMethod. --- .../Generation/InteropGenerator.Emit.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index e99445de9..b62e122dd 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -2039,6 +2039,20 @@ private static void RewriteMethodDefinitions( emitState: emitState, module: module); break; + + // Rewrite native parameters + case MethodRewriteInfo.NativeParameter nativeParameterInfo: + InteropMethodRewriteFactory.NativeParameter.RewriteMethod( + parameterType: nativeParameterInfo.Type, + method: nativeParameterInfo.Method, + tryMarker: nativeParameterInfo.TryMarker, + loadMarker: nativeParameterInfo.Marker, + finallyMarker: nativeParameterInfo.FinallyMarker, + parameterIndex: nativeParameterInfo.ParameterIndex, + interopReferences: interopReferences, + emitState: emitState, + module: module); + break; default: throw new UnreachableException(); } } From 872290d56437ad181bb4a88545ce887e9f4164ab Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:25:10 -0800 Subject: [PATCH 11/31] Add tracking for native parameter method rewrites Introduces the TrackNativeParameterMethodRewrite method to track method rewrites involving native parameters, complementing the existing managed parameter tracking. Updates XML documentation to clarify the distinction between managed and native parameter rewrites. --- .../Generation/InteropGeneratorEmitState.cs | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs b/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs index 52a4f2a8c..960245150 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs @@ -128,7 +128,7 @@ public void TrackRetValValueMethodRewrite( } /// - /// Tracks a method rewrite that involves loading a parameter in the specified method. + /// Tracks a method rewrite that involves loading a managed parameter in the specified method. /// /// /// @@ -151,6 +151,36 @@ public void TrackManagedParameterMethodRewrite( }); } + /// + /// Tracks a method rewrite that involves loading a native parameter in the specified method. + /// + /// + /// + /// + /// + /// + /// + public void TrackNativeParameterMethodRewrite( + TypeSignature paraneterType, + MethodDefinition method, + CilInstruction tryMarker, + CilInstruction loadMarker, + CilInstruction finallyMarker, + int parameterIndex) + { + ThrowIfReadOnly(); + + _methodRewriteInfos.Add(new MethodRewriteInfo.NativeParameter + { + Type = paraneterType, + Method = method, + TryMarker = tryMarker, + Marker = loadMarker, + FinallyMarker = finallyMarker, + ParameterIndex = parameterIndex + }); + } + /// /// Enumerates all instances with info on two-pass code generation steps to perform. /// From ce92a0a209458a4cb5e3e7ed486e9272f8f090a2 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:27:31 -0800 Subject: [PATCH 12/31] Add emitState tracking to NativeDelegateType method The NativeDelegateType method now accepts an InteropGeneratorEmitState parameter and uses it to track native parameter method rewrites for delegate parameters. This change enables better tracking and management of parameter rewrites during interop delegate generation. --- .../InteropTypeDefinitionBuilder.Delegate.cs | 21 +++++++++++++++++-- .../Generation/InteropGenerator.Emit.cs | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index e491c0345..7cb24f3a2 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -401,12 +401,14 @@ public static void ComWrappersCallbackType( /// The for the type. /// The instance to use. /// The instance to use. + /// The emit state for this invocation. /// The interop module being built. /// The resulting callback type. public static void NativeDelegateType( GenericInstanceTypeSignature delegateType, InteropDefinitions interopDefinitions, InteropReferences interopReferences, + InteropGeneratorEmitState emitState, ModuleDefinition module, out TypeDefinition nativeDelegateType) { @@ -485,8 +487,6 @@ public static void NativeDelegateType( { Ldloc_1 }, { nop_ld_sender }, { nop_ld_args }, - { Ldnull }, // TODO: remove - { Ldnull }, // TODO: remove { Ldloc_1 }, { Ldind_I }, { Ldfld, interopDefinitions.DelegateVftbl.Fields[3] }, @@ -520,6 +520,23 @@ public static void NativeDelegateType( } } }; + + // Track rewriting the two parameters for this method + emitState.TrackNativeParameterMethodRewrite( + paraneterType: senderType, + method: invokeMethod, + tryMarker: nop_try_sender, + loadMarker: nop_ld_sender, + finallyMarker: nop_finally_sender, + parameterIndex: 1); + + emitState.TrackNativeParameterMethodRewrite( + paraneterType: argsType, + method: invokeMethod, + tryMarker: nop_try_args, + loadMarker: nop_ld_args, + finallyMarker: nop_finally_args, + parameterIndex: 2); } /// diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index b62e122dd..a939fc19f 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -276,6 +276,7 @@ private static void DefineGenericDelegateTypes( delegateType: typeSignature, interopDefinitions: interopDefinitions, interopReferences: interopReferences, + emitState: emitState, module: module, nativeDelegateType: out TypeDefinition nativeDelegateType); From 250a2b9c6097811bf42b2df38a5f59bb574f4133 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:48:04 -0800 Subject: [PATCH 13/31] Add IListExtensions with ReferenceIndexOf method Introduces an extension for IList that provides ReferenceIndexOf, which returns the index of an item using reference equality instead of value equality. --- .../Extensions/IListExtensions.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/WinRT.Interop.Generator/Extensions/IListExtensions.cs diff --git a/src/WinRT.Interop.Generator/Extensions/IListExtensions.cs b/src/WinRT.Interop.Generator/Extensions/IListExtensions.cs new file mode 100644 index 000000000..7c2b60447 --- /dev/null +++ b/src/WinRT.Interop.Generator/Extensions/IListExtensions.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Generic; + +namespace WindowsRuntime.InteropGenerator; + +/// +/// Extensions for the type. +/// +internal static class IListExtensions +{ + extension(IList list) + where T : class + { + /// + /// + /// This method only ever compares values by reference equality. + /// + public int ReferenceIndexOf(T value) + { + for (int i = 0; i < list.Count; i++) + { + if (ReferenceEquals(list[i], value)) + { + return i; + } + } + + return -1; + } + } +} \ No newline at end of file From 311343de52b6a2a38e5e7fabecd55c7aa9fbb52a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:49:57 -0800 Subject: [PATCH 14/31] Add ReferenceContains method to IListExtensions Introduces ReferenceContains, which checks for reference equality in IList. This provides a way to determine if a specific object instance exists in the list, complementing the existing ReferenceIndexOf method. --- .../Extensions/IListExtensions.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/WinRT.Interop.Generator/Extensions/IListExtensions.cs b/src/WinRT.Interop.Generator/Extensions/IListExtensions.cs index 7c2b60447..d28c7461e 100644 --- a/src/WinRT.Interop.Generator/Extensions/IListExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/IListExtensions.cs @@ -13,6 +13,15 @@ internal static class IListExtensions extension(IList list) where T : class { + /// + /// + /// This method only ever compares values by reference equality. + /// + public bool ReferenceContains(T value) + { + return list.Count != 0 && list.ReferenceIndexOf(value) >= 0; + } + /// /// /// This method only ever compares values by reference equality. From c766bc1577f5b26fd030c6558bb85de74786dea0 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:52:27 -0800 Subject: [PATCH 15/31] Use reference-based collection methods for instruction checks Replaces value-based Contains and IndexOf calls with new ReferenceContains and ReferenceIndexOf methods to ensure instruction and local variable checks are performed by reference equality. This improves correctness when working with IL instruction collections where object identity matters. --- .../CilInstructionCollectionExtensions.cs | 14 ++------------ ...InteropMethodRewriteFactory.ManagedParameter.cs | 2 +- .../InteropMethodRewriteFactory.NativeParameter.cs | 2 +- .../InteropMethodRewriteFactory.RetVal.cs | 2 +- .../InteropMethodRewriteFactory.ReturnValue.cs | 4 ++-- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs b/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs index d0e67048f..45d5ba62c 100644 --- a/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs @@ -22,20 +22,10 @@ internal static class CilInstructionCollectionExtensions /// The new instructions to emit. public void ReplaceRange(CilInstruction target, params IEnumerable values) { - int index; - - // Find the index of the target instruction in the collection. - // We can't use 'IndexOf', as we only want to match by reference. - for (index = 0; index < instructions.Count; index++) - { - if (instructions[index] == target) - { - break; - } - } + int index = instructions.ReferenceIndexOf(target); // Ensure we did find the target instruction - if (index >= instructions.Count) + if (index == -1) { throw new ArgumentException("The target instruction was not found in the collection.", nameof(target)); } diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs index e8114a61c..fea872d17 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs @@ -47,7 +47,7 @@ public static void RewriteMethod( } // If we didn't find the marker, it means the target method is either invalid - if (!body.Instructions.Contains(marker)) + if (!body.Instructions.ReferenceContains(marker)) { throw WellKnownInteropExceptions.MethodRewriteMarkerInstructionNotFoundError(marker, method); } diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs index 98b17b330..3787593e5 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs @@ -56,7 +56,7 @@ public static void RewriteMethod( // If we didn't find any of markers, it means the target method is either invalid foreach (CilInstruction marker in (ReadOnlySpan)[tryMarker, loadMarker, finallyMarker]) { - if (!body.Instructions.Contains(marker)) + if (!body.Instructions.ReferenceContains(marker)) { throw WellKnownInteropExceptions.MethodRewriteMarkerInstructionNotFoundError(marker, method); } diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.RetVal.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.RetVal.cs index a33b21bd9..49961b23a 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.RetVal.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.RetVal.cs @@ -60,7 +60,7 @@ public static void RewriteMethod( // If we didn't find the marker, it means the target method is either invalid, or the // supplied marker was incorrect (or the caller forgot to add it to the method body). - if (!body.Instructions.Contains(marker)) + if (!body.Instructions.ReferenceContains(marker)) { throw WellKnownInteropExceptions.MethodRewriteMarkerInstructionNotFoundError(marker, method); } diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs index 674e05df2..6ba691feb 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs @@ -49,13 +49,13 @@ public static void RewriteMethod( // If we didn't find the marker, it means the target method is either invalid, or the // supplied marker was incorrect (or the caller forgot to add it to the method body). - if (!body.Instructions.Contains(marker)) + if (!body.Instructions.ReferenceContains(marker)) { throw WellKnownInteropExceptions.MethodRewriteMarkerInstructionNotFoundError(marker, method); } // Also validate that the target local variable is also actually part of the method - if (!body.LocalVariables.Contains(source)) + if (!body.LocalVariables.ReferenceContains(source)) { throw WellKnownInteropExceptions.MethodRewriteSourceLocalNotFoundError(source, method); } From f47b27a611ef65181c410689a0f868d80d9f80b9 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 11:46:05 -0800 Subject: [PATCH 16/31] Add ReferenceRemove and ReferenceRemoveRange extensions Introduces ReferenceRemove to IListExtensions for removing items by reference equality, and ReferenceRemoveRange to CilInstructionCollectionExtensions for batch removal. Also updates ReplaceRange to use consistent parameter naming. --- .../CilInstructionCollectionExtensions.cs | 18 +++++++++++++++--- .../Extensions/IListExtensions.cs | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs b/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs index 45d5ba62c..79a35fb1a 100644 --- a/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs @@ -15,12 +15,24 @@ internal static class CilInstructionCollectionExtensions { extension(CilInstructionCollection instructions) { + /// + /// Removes a set of CIL instructions from the collection. + /// + /// The instructions to remove. + public void ReferenceRemoveRange(params IEnumerable items) + { + foreach (CilInstruction item in items) + { + _ = instructions.ReferenceRemove(item); + } + } + /// /// Replaces a target instruction with a collection of new instructions. /// /// The instruction to replace. - /// The new instructions to emit. - public void ReplaceRange(CilInstruction target, params IEnumerable values) + /// The new instructions to emit. + public void ReplaceRange(CilInstruction target, params IEnumerable items) { int index = instructions.ReferenceIndexOf(target); @@ -31,7 +43,7 @@ public void ReplaceRange(CilInstruction target, params IEnumerable= 0; } + /// + /// + /// This method only ever compares values by reference equality. + /// + public bool ReferenceRemove(T value) + { + int index = list.ReferenceIndexOf(value); + + if (index >= 0) + { + list.RemoveAt(index); + + return true; + } + + return false; + } + /// /// /// This method only ever compares values by reference equality. From dc5f9fca5c425abfb3ada0219fe7ca570cbb38b2 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 11:54:40 -0800 Subject: [PATCH 17/31] Rename ReplaceRange to ReferenceReplaceRange in instruction helpers Refactored method names from ReplaceRange to ReferenceReplaceRange and RemoveRange to ReferenceRemoveRange in CilInstructionCollectionExtensions and related factory classes to clarify usage of reference-based instruction replacement and removal. This improves code readability and consistency across instruction manipulation logic. --- .../CilInstructionCollectionExtensions.cs | 2 +- ...opMethodRewriteFactory.ManagedParameter.cs | 14 +++++----- ...ropMethodRewriteFactory.NativeParameter.cs | 26 +++++++++---------- .../InteropMethodRewriteFactory.RetVal.cs | 12 ++++----- ...InteropMethodRewriteFactory.ReturnValue.cs | 8 +++--- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs b/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs index 79a35fb1a..100916eae 100644 --- a/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/CilInstructionCollectionExtensions.cs @@ -32,7 +32,7 @@ public void ReferenceRemoveRange(params IEnumerable items) /// /// The instruction to replace. /// The new instructions to emit. - public void ReplaceRange(CilInstruction target, params IEnumerable items) + public void ReferenceReplaceRange(CilInstruction target, params IEnumerable items) { int index = instructions.ReferenceIndexOf(target); diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs index fea872d17..e4e1003d0 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs @@ -71,12 +71,12 @@ public static void RewriteMethod( // If the return type is blittable, we can just load it directly it directly (simplest case) if (parameterType.IsBlittable(interopReferences)) { - body.Instructions.ReplaceRange(marker, CilInstruction.CreateLdarg(parameterIndex)); + body.Instructions.ReferenceReplaceRange(marker, CilInstruction.CreateLdarg(parameterIndex)); } else if (parameterType.IsConstructedKeyValuePairType(interopReferences)) { // If the type is some constructed 'KeyValuePair<,>' type, we use the generated marshaller - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, emitState.LookupTypeDefinition(parameterType, "Marshaller").GetMethod("ConvertToManaged"))]); } @@ -95,7 +95,7 @@ public static void RewriteMethod( parameterTypes: [module.CorLibTypeFactory.Void.MakePointerType()])); // Emit code similar to 'KeyValuePair<,>' above, to marshal the resulting 'Nullable' value - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, marshallerMethod.Import(module))]); } @@ -113,7 +113,7 @@ public static void RewriteMethod( parameterTypes: [parameterType.GetAbiType(interopReferences)])); // We can directly call the marshaller and return it, no 'try/finally' complexity is needed - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, marshallerMethod.Import(module))]); } @@ -121,14 +121,14 @@ public static void RewriteMethod( else if (parameterType.IsTypeOfString()) { // When marshalling 'string' values, we must use 'HStringMarshaller' (the ABI type is not actually a COM object) - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, interopReferences.HStringMarshallerConvertToManaged.Import(module))]); } else if (parameterType is GenericInstanceTypeSignature) { // This case (constructed interfaces or delegates) is effectively identical to marshalling 'KeyValuePair<,>' values - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, emitState.LookupTypeDefinition(parameterType, "Marshaller").GetMethod("ConvertToManaged"))]); } @@ -145,7 +145,7 @@ public static void RewriteMethod( parameterTypes: [module.CorLibTypeFactory.Void.MakePointerType()])); // Marshal the value and release the original interface pointer - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, marshallerMethod.Import(module))]); } diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs index 3787593e5..ba282fe77 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs @@ -81,8 +81,8 @@ public static void RewriteMethod( // If the return type is blittable, we can just load it directly it directly (simplest case) if (parameterType.IsBlittable(interopReferences)) { - body.Instructions.RemoveRange([tryMarker, finallyMarker]); - body.Instructions.ReplaceRange(loadMarker, CilInstruction.CreateLdarg(parameterIndex)); + body.Instructions.ReferenceRemoveRange(tryMarker, finallyMarker); + body.Instructions.ReferenceReplaceRange(loadMarker, CilInstruction.CreateLdarg(parameterIndex)); } else if (parameterType.IsConstructedKeyValuePairType(interopReferences)) { @@ -159,20 +159,20 @@ public static void RewriteMethod( else if (parameterType.IsTypeOfString()) { // TODO - body.Instructions.RemoveRange([tryMarker, finallyMarker]); - body.Instructions.ReplaceRange(loadMarker, new CilInstruction(Ldnull)); + body.Instructions.ReferenceRemoveRange(tryMarker, finallyMarker); + body.Instructions.ReferenceReplaceRange(loadMarker, new CilInstruction(Ldnull)); } else if (parameterType.IsTypeOfType(interopReferences)) { // TODO - body.Instructions.RemoveRange([tryMarker, finallyMarker]); - body.Instructions.ReplaceRange(loadMarker, new CilInstruction(Ldnull)); + body.Instructions.ReferenceRemoveRange(tryMarker, finallyMarker); + body.Instructions.ReferenceReplaceRange(loadMarker, new CilInstruction(Ldnull)); } else if (parameterType.IsTypeOfException(interopReferences)) { // The ABI type of 'Exception' is unmanaged, so we can marshal the value directly - body.Instructions.RemoveRange([tryMarker, finallyMarker]); - body.Instructions.ReplaceRange(loadMarker, [ + body.Instructions.ReferenceRemoveRange(tryMarker, finallyMarker); + body.Instructions.ReferenceReplaceRange(loadMarker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, interopReferences.ExceptionMarshallerConvertToUnmanaged.Import(module))]); } @@ -234,7 +234,7 @@ private static void RewriteBody( CilInstruction nop_finallyEnd = new(Nop); // Marshal the value before the call - body.Instructions.ReplaceRange(tryMarker, [ + body.Instructions.ReferenceReplaceRange(tryMarker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, marshallerMethod.Import(module)), CilInstruction.CreateStloc(loc_parameter, body), @@ -244,13 +244,13 @@ private static void RewriteBody( // we'll get the pointer from it. Otherwise, we just load the ABI value and pass it directly to native. if (parameterAbiType.IsTypeOfVoidPointer()) { - body.Instructions.ReplaceRange(loadMarker, [ + body.Instructions.ReferenceReplaceRange(loadMarker, [ new CilInstruction(Ldloca_S, loc_parameter), new CilInstruction(Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module))]); } else { - body.Instructions.ReplaceRange(loadMarker, CilInstruction.CreateLdloc(loc_parameter, body)); + body.Instructions.ReferenceReplaceRange(loadMarker, CilInstruction.CreateLdloc(loc_parameter, body)); } // Release the ABI value, or the 'WindowsRuntimeObjectReferenceValue' value, after the call. @@ -261,7 +261,7 @@ private static void RewriteBody( { ldloc_or_a_finallyStart = new CilInstruction(Ldloca_S, loc_parameter); - body.Instructions.ReplaceRange(finallyMarker, [ + body.Instructions.ReferenceReplaceRange(finallyMarker, [ ldloc_or_a_finallyStart, new CilInstruction(Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module)), new CilInstruction(Endfinally), @@ -271,7 +271,7 @@ private static void RewriteBody( { ldloc_or_a_finallyStart = CilInstruction.CreateLdloc(loc_parameter, body); - body.Instructions.ReplaceRange(finallyMarker, [ + body.Instructions.ReferenceReplaceRange(finallyMarker, [ ldloc_or_a_finallyStart, new CilInstruction(Call, disposeMethod!.Import(module)), new CilInstruction(Endfinally), diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.RetVal.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.RetVal.cs index 49961b23a..6188ebdc9 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.RetVal.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.RetVal.cs @@ -89,7 +89,7 @@ public static void RewriteMethod( _ => new CilInstruction(Stobj, retValType.Import(module).ToTypeDefOrRef()), }; - body.Instructions.ReplaceRange(marker, [storeInstruction]); + body.Instructions.ReferenceReplaceRange(marker, [storeInstruction]); } else if (retValType.IsConstructedKeyValuePairType(interopReferences)) { @@ -137,7 +137,7 @@ public static void RewriteMethod( parameterTypes: [retValType.GetAbiType(interopReferences)])); // Delegate to the marshaller to convert the managed value type on the evaluation stack - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ new CilInstruction(Call, marshallerMethod.Import(module)), new CilInstruction(Stobj, retValType.GetAbiType(interopReferences).Import(module).ToTypeDefOrRef())]); } @@ -145,21 +145,21 @@ public static void RewriteMethod( else if (retValType.IsTypeOfString()) { // When marshalling 'string' values, we must use 'HStringMarshaller' - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ new CilInstruction(Call, interopReferences.HStringMarshallerConvertToUnmanaged.Import(module)), new CilInstruction(Stind_I)]); } else if (retValType.IsTypeOfType(interopReferences)) { // 'Type' values also need their own specialized marshaller - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ new CilInstruction(Call, interopReferences.TypeMarshallerConvertToUnmanaged.Import(module)), new CilInstruction(Stobj, interopReferences.AbiType.Import(module).ToTypeDefOrRef())]); } else if (retValType.IsTypeOfException(interopReferences)) { // 'Exception' is also special, and needs its own specialized marshaller - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ new CilInstruction(Call, interopReferences.ExceptionMarshallerConvertToUnmanaged.Import(module)), new CilInstruction(Stobj, interopReferences.AbiException.Import(module).ToTypeDefOrRef())]); } @@ -213,7 +213,7 @@ private static void RewriteBody( body.LocalVariables.Add(loc_returnValue); // Marshal the value and detach its native pointer before assigning it to the target location - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ new CilInstruction(Call, marshallerMethod.Import(module)), CilInstruction.CreateStloc(loc_returnValue, body), new CilInstruction(Ldloca_S, loc_returnValue), diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs index 6ba691feb..d0e1e6785 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ReturnValue.cs @@ -71,7 +71,7 @@ public static void RewriteMethod( // If the return type is blittable, we can always return it directly (simplest case) if (returnType.IsBlittable(interopReferences)) { - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdloc(source, body), new CilInstruction(Ret)]); } @@ -161,7 +161,7 @@ public static void RewriteMethod( parameterTypes: [returnType.GetAbiType(interopReferences)])); // We can directly call the marshaller and return it, no 'try/finally' complexity is needed - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdloc(source, body), new CilInstruction(Call, marshallerMethod.Import(module)), new CilInstruction(Ret)]); @@ -194,7 +194,7 @@ public static void RewriteMethod( else if (returnType.IsTypeOfException(interopReferences)) { // 'Exception' is also special, though it's simple: the ABI type is an unmanaged value type - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdloc(source, body), new CilInstruction(Call, interopReferences.ExceptionMarshallerConvertToManaged.Import(module)), new CilInstruction(Ret)]); @@ -263,7 +263,7 @@ private static void RewriteBody( CilInstruction ldloc_finallyEnd = CilInstruction.CreateLdloc(loc_returnValue, body); // Marshal the value and release the original interface pointer, or dispose the ABI value - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ ldloc_tryStart, new CilInstruction(Call, marshallerMethod.Import(module)), CilInstruction.CreateStloc(loc_returnValue, body), From 7ef6023a0c9c337ca71127e8d43fae2daeb0bba2 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 12:13:13 -0800 Subject: [PATCH 18/31] Refactor MethodRewriteInfo comparison logic Standardizes and improves the comparison logic for MethodRewriteInfo and its subclasses. Introduces a generic CompareByMethodRewriteInfo method, uses MemberDefinitionComparer and TypeDescriptorComparer for consistent ordering, and ensures instruction and parameter indices are compared using ReferenceIndexOf for accuracy. Cleans up redundant code and clarifies comparison order for ManagedParameter, NativeParameter, ReturnValue, and RetVal. --- .../MethodRewriteInfo.ManagedParameter.cs | 34 +++++++++++---- .../MethodRewriteInfo.NativeParameter.cs | 42 +++++++++---------- .../MethodRewriteInfo.RetVal.cs | 18 ++------ .../MethodRewriteInfo.ReturnValue.cs | 21 ++-------- .../MethodRewriteInfo/MethodRewriteInfo.cs | 37 ++++++++++------ 5 files changed, 79 insertions(+), 73 deletions(-) diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs index 769ff45ac..010c753bf 100644 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ManagedParameter.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using WindowsRuntime.InteropGenerator.Helpers; + namespace WindowsRuntime.InteropGenerator.Models; /// @@ -23,27 +25,41 @@ public override int CompareTo(MethodRewriteInfo? other) return 1; } - if (ReferenceEquals(this, other)) - { - return 0; - } - // If the input object is of a different type, just sort alphabetically based on the type name if (other is not ManagedParameter info) { return typeof(ManagedParameter).FullName!.CompareTo(other.GetType().FullName!); } - int result = CompareByMethodRewriteInfo(other); + int result = MemberDefinitionComparer.Instance.Compare(Method, other.Method); + + // First, sort by target method + if (result != 0) + { + return result; + } + + // Next, sort by parameter index + result = ParameterIndex.CompareTo(info.ParameterIndex); + + if (result != 0) + { + return result; + } + + // Next, compare by order of instructions within the target method + int leftIndex = Method.CilMethodBody?.Instructions.ReferenceIndexOf(Marker) ?? -1; + int rightIndex = other.Method.CilMethodBody?.Instructions.ReferenceIndexOf(other.Marker) ?? -1; + + result = leftIndex.CompareTo(rightIndex); - // If the two items are already not equal, we can stop here if (result != 0) { return result; } - // Lastly, compare by parameter index - return ParameterIndex.CompareTo(info.ParameterIndex); + // Lastly, compare by target type (this shouldn't be reached for valid objects) + return TypeDescriptorComparer.Instance.Compare(Type, other.Type); } } } diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.NativeParameter.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.NativeParameter.cs index 49b2a1ba9..65884e8f9 100644 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.NativeParameter.cs +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.NativeParameter.cs @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System; using AsmResolver.PE.DotNet.Cil; +using WindowsRuntime.InteropGenerator.Helpers; namespace WindowsRuntime.InteropGenerator.Models; @@ -31,49 +33,47 @@ public override int CompareTo(MethodRewriteInfo? other) return 1; } - if (ReferenceEquals(this, other)) - { - return 0; - } - // If the input object is of a different type, just sort alphabetically based on the type name if (other is not NativeParameter info) { return typeof(NativeParameter).FullName!.CompareTo(other.GetType().FullName!); } - int result = CompareByMethodRewriteInfo(other); + int result = MemberDefinitionComparer.Instance.Compare(Method, other.Method); - // If the two items are already not equal, we can stop here + // First, sort by target method if (result != 0) { return result; } - int leftIndex = Method.CilMethodBody?.Instructions.IndexOf(TryMarker) ?? -1; - int rightIndex = other.Method.CilMethodBody?.Instructions.IndexOf(info.TryMarker) ?? -1; + // Next, sort by parameter index + result = ParameterIndex.CompareTo(info.ParameterIndex); - result = leftIndex.CompareTo(rightIndex); - - // Compare by the position of the marker for the 'try' block if (result != 0) { return result; } - leftIndex = Method.CilMethodBody?.Instructions.IndexOf(FinallyMarker) ?? -1; - rightIndex = other.Method.CilMethodBody?.Instructions.IndexOf(info.FinallyMarker) ?? -1; - - result = leftIndex.CompareTo(rightIndex); + ReadOnlySpan markers = [TryMarker, Marker, FinallyMarker]; + ReadOnlySpan otherMarkers = [info.TryMarker, info.Marker, info.FinallyMarker]; - // Next, compare by the position of the marker for the 'finally' block - if (result != 0) + // Next, compare by order of instructions within the target method + for (int i = 0; i < markers.Length; i++) { - return result; + int leftIndex = Method.CilMethodBody?.Instructions.ReferenceIndexOf(markers[i]) ?? -1; + int rightIndex = other.Method.CilMethodBody?.Instructions.ReferenceIndexOf(otherMarkers[i]) ?? -1; + + result = leftIndex.CompareTo(rightIndex); + + if (result != 0) + { + return result; + } } - // Lastly, compare by parameter index - return ParameterIndex.CompareTo(info.ParameterIndex); + // Lastly, compare by target type (this shouldn't be reached for valid objects) + return TypeDescriptorComparer.Instance.Compare(Type, other.Type); } } } diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.RetVal.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.RetVal.cs index d86d21e98..821989703 100644 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.RetVal.cs +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.RetVal.cs @@ -15,20 +15,10 @@ public sealed class RetVal : MethodRewriteInfo /// public override int CompareTo(MethodRewriteInfo? other) { - if (other is null) - { - return 1; - } - - if (ReferenceEquals(this, other)) - { - return 0; - } - - // Same logic as in 'ReturnValue', or just compare the base state - return other is not RetVal - ? typeof(RetVal).FullName!.CompareTo(other.GetType().FullName!) - : CompareByMethodRewriteInfo(other); + // 'RetVal' objects have no additional state, so just compare with the base state + return ReferenceEquals(this, other) + ? 0 + : CompareByMethodRewriteInfo(other); } } } diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ReturnValue.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ReturnValue.cs index 6fdf333ca..452e75d26 100644 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ReturnValue.cs +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.ReturnValue.cs @@ -20,36 +20,23 @@ public sealed class ReturnValue : MethodRewriteInfo /// public override int CompareTo(MethodRewriteInfo? other) { - if (other is null) - { - return 1; - } - if (ReferenceEquals(this, other)) { return 0; } - // If the input object is of a different type, just sort alphabetically based on the type name - if (other is not ReturnValue info) - { - return typeof(ReturnValue).FullName!.CompareTo(other.GetType().FullName!); - } - - int result = CompareByMethodRewriteInfo(other); + int result = CompareByMethodRewriteInfo(other); - // If the two items are already not equal, we can stop here + // First, compare with the base state if (result != 0) { return result; } int leftIndex = Method.CilMethodBody?.LocalVariables.IndexOf(Source) ?? -1; - int rightIndex = other.Method.CilMethodBody?.LocalVariables.IndexOf(info.Source) ?? -1; + int rightIndex = other!.Method.CilMethodBody?.LocalVariables.IndexOf(((ReturnValue)other).Source) ?? -1; - // Lastly, compare by order of instructions within the target method. - // There's no concern about stable sorting with respect to objects - // where the instructions are missing, as 'cswinrtgen' will fail. + // Lastly, compare by the order of the source variable return leftIndex.CompareTo(rightIndex); } } diff --git a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.cs b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.cs index 0790df9fe..06d2afec5 100644 --- a/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.cs +++ b/src/WinRT.Interop.Generator/Models/MethodRewriteInfo/MethodRewriteInfo.cs @@ -31,32 +31,45 @@ internal abstract partial class MethodRewriteInfo : IComparable /// Compares the current instance just based on the state from . /// + /// The type currently in use. /// The input instance. /// The comparison result. - protected int CompareByMethodRewriteInfo(MethodRewriteInfo other) + protected int CompareByMethodRewriteInfo(MethodRewriteInfo? other) + where T : MethodRewriteInfo { - int result = TypeDescriptorComparer.Instance.Compare(Type, other.Type); + if (other is null) + { + return 1; + } - // Match by marshalling type first - if (result != 0) + // If the input object is of a different type, just sort alphabetically based on the type name + if (other is not T) { - return result; + return typeof(T).FullName!.CompareTo(other.GetType().FullName!); } - result = MemberDefinitionComparer.Instance.Compare(Method, other.Method); + int result = MemberDefinitionComparer.Instance.Compare(Method, other.Method); - // Match by target method next + // First, sort by target method if (result != 0) { return result; } - int leftIndex = Method.CilMethodBody?.Instructions.IndexOf(Marker) ?? -1; - int rightIndex = other.Method.CilMethodBody?.Instructions.IndexOf(other.Marker) ?? -1; - - // Lastly, compare by order of instructions within the target method. + // Next, compare by order of instructions within the target method. // There's no concern about stable sorting with respect to objects // where the instructions are missing, as 'cswinrtgen' will fail. - return leftIndex.CompareTo(rightIndex); + int leftIndex = Method.CilMethodBody?.Instructions.ReferenceIndexOf(Marker) ?? -1; + int rightIndex = other.Method.CilMethodBody?.Instructions.ReferenceIndexOf(other.Marker) ?? -1; + + result = leftIndex.CompareTo(rightIndex); + + if (result != 0) + { + return result; + } + + // Lastly, compare by target type (this shouldn't be reached for valid objects) + return TypeDescriptorComparer.Instance.Compare(Type, other.Type); } } From 4840649d7561c054ced7d809753141efe8194dec Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 12:22:09 -0800 Subject: [PATCH 19/31] Refactor vtable sharing checks to use ABI type void* Updated logic in InteropTypeDefinitionBuilder for IList, IReadOnlyList, IDictionary, and IReadOnlyDictionary to determine vtable sharing based on whether the ABI type is 'void*' using GetAbiType().IsTypeOfVoidPointer(), instead of checking for reference types or KeyValuePair types. This improves accuracy and consistency in vtable sharing decisions. --- .../Builders/InteropTypeDefinitionBuilder.IDictionary2.cs | 4 ++-- .../Builders/InteropTypeDefinitionBuilder.IList1.cs | 5 ++--- .../InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs | 2 +- .../Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs index 36b170243..085bafa6a 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs @@ -89,8 +89,8 @@ public static void Vftbl( TypeSignature keyType = dictionaryType.TypeArguments[0]; TypeSignature valueType = dictionaryType.TypeArguments[1]; - bool isKeyReferenceType = !keyType.IsValueType || keyType.IsConstructedKeyValuePairType(interopReferences); - bool isValueReferenceType = !valueType.IsValueType || valueType.IsConstructedKeyValuePairType(interopReferences); + bool isKeyReferenceType = keyType.GetAbiType(interopReferences).IsTypeOfVoidPointer(); + bool isValueReferenceType = keyType.GetAbiType(interopReferences).IsTypeOfVoidPointer(); // We can share the vtable type for 'void*' when both key and value types are reference types if (isKeyReferenceType && isValueReferenceType) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs index f4a5e8999..2d239ce32 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs @@ -86,9 +86,8 @@ public static void Vftbl( { TypeSignature elementType = listType.TypeArguments[0]; - // All reference types can share the same vtable type (as it just uses 'void*' for the ABI type). - // We can also share vtables for 'KeyValuePair<,>' types, as their ABI type is an interface. - if (!elementType.IsValueType || elementType.IsConstructedKeyValuePairType(interopReferences)) + // For types which use 'void*' as their ABI types, we can share the same vtable type definition + if (elementType.GetAbiType(interopReferences).IsTypeOfVoidPointer()) { vftblType = interopDefinitions.IList1Vftbl; diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs index 179251ee8..3f7bd8beb 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs @@ -43,7 +43,7 @@ public static void Vftbl( // All reference types can share the same vtable type (as it just uses 'void*' for the ABI type). // The 'IMapView' interface doesn't use 'V' as a by-value parameter anywhere in the vtable, // so we can aggressively share vtable types for all cases where 'K' is a reference type. - if (!keyType.IsValueType || keyType.IsConstructedKeyValuePairType(interopReferences)) + if (keyType.GetAbiType(interopReferences).IsTypeOfVoidPointer()) { vftblType = interopDefinitions.IReadOnlyDictionary2Vftbl; diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs index 7e78946a9..d3c237ede 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs @@ -39,7 +39,7 @@ public static void Vftbl( TypeSignature elementType = readOnlyListType.TypeArguments[0]; // Same logic as with 'IList1.Vftbl' (i.e. share for all reference types) - if (!elementType.IsValueType || elementType.IsConstructedKeyValuePairType(interopReferences)) + if (elementType.GetAbiType(interopReferences).IsTypeOfVoidPointer()) { vftblType = interopDefinitions.IReadOnlyList1Vftbl; From cd48e289b030b8fe0ffdf5300b8b074547c6f53b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 12:38:17 -0800 Subject: [PATCH 20/31] Add HasReferenceAbiType method to WindowsRuntimeExtensions Introduces the HasReferenceAbiType method to determine if a type uses a reference ABI type, handling generics, value types, and special cases like Type and Exception. This aids in ABI type resolution for interop scenarios. --- .../Extensions/WindowsRuntimeExtensions.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs index 07d7f65d5..7564c5550 100644 --- a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs @@ -486,6 +486,41 @@ public bool IsTrackerSupportRequired(InteropReferences interopReferences) return false; } + /// + /// Gets the ABI type for a given type. + /// + /// The instance to use. + /// The ABi type for the input type. + public bool HasReferenceAbiType(InteropReferences interopReferences) + { + // All constructed generics will use 'void*' for the ABI type + if (type is GenericInstanceTypeSignature) + { + return true; + } + + // All other value types will never have a reference type as the ABI type + if (type.IsValueType) + { + return false; + } + + // 'Type' is a class, but is custom-mapped to the 'TypeName' struct type + if (SignatureComparer.IgnoreVersion.Equals(type, interopReferences.Type)) + { + return false; + } + + // 'Exception' is also a class, but is custom-mapped to the 'HResult' struct type + if (SignatureComparer.IgnoreVersion.Equals(type, interopReferences.Exception)) + { + return false; + } + + // For all other cases (e.g. interfaces, classes, delegates, etc.), the ABI type is always a pointer + return true; + } + /// /// Gets the ABI type for a given type. /// From acee4a40632f4939c15f52213c921e666a8c3f9c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 12:39:59 -0800 Subject: [PATCH 21/31] Refactor ABI type checks to use HasReferenceAbiType Replaces calls to GetAbiType(...).IsTypeOfVoidPointer() with HasReferenceAbiType(...) for improved clarity and consistency when determining if types use reference ABI types in interop builders. --- .../Builders/InteropTypeDefinitionBuilder.IDictionary2.cs | 4 ++-- .../Builders/InteropTypeDefinitionBuilder.IList1.cs | 2 +- .../InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs | 2 +- .../Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs index 085bafa6a..931484484 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs @@ -89,8 +89,8 @@ public static void Vftbl( TypeSignature keyType = dictionaryType.TypeArguments[0]; TypeSignature valueType = dictionaryType.TypeArguments[1]; - bool isKeyReferenceType = keyType.GetAbiType(interopReferences).IsTypeOfVoidPointer(); - bool isValueReferenceType = keyType.GetAbiType(interopReferences).IsTypeOfVoidPointer(); + bool isKeyReferenceType = keyType.HasReferenceAbiType(interopReferences); + bool isValueReferenceType = keyType.HasReferenceAbiType(interopReferences); // We can share the vtable type for 'void*' when both key and value types are reference types if (isKeyReferenceType && isValueReferenceType) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs index 2d239ce32..70df2b95b 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs @@ -87,7 +87,7 @@ public static void Vftbl( TypeSignature elementType = listType.TypeArguments[0]; // For types which use 'void*' as their ABI types, we can share the same vtable type definition - if (elementType.GetAbiType(interopReferences).IsTypeOfVoidPointer()) + if (elementType.HasReferenceAbiType(interopReferences)) { vftblType = interopDefinitions.IList1Vftbl; diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs index 3f7bd8beb..5a212b348 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs @@ -43,7 +43,7 @@ public static void Vftbl( // All reference types can share the same vtable type (as it just uses 'void*' for the ABI type). // The 'IMapView' interface doesn't use 'V' as a by-value parameter anywhere in the vtable, // so we can aggressively share vtable types for all cases where 'K' is a reference type. - if (keyType.GetAbiType(interopReferences).IsTypeOfVoidPointer()) + if (keyType.HasReferenceAbiType(interopReferences)) { vftblType = interopDefinitions.IReadOnlyDictionary2Vftbl; diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs index d3c237ede..af61f50d6 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs @@ -39,7 +39,7 @@ public static void Vftbl( TypeSignature elementType = readOnlyListType.TypeArguments[0]; // Same logic as with 'IList1.Vftbl' (i.e. share for all reference types) - if (elementType.GetAbiType(interopReferences).IsTypeOfVoidPointer()) + if (elementType.HasReferenceAbiType(interopReferences)) { vftblType = interopDefinitions.IReadOnlyList1Vftbl; From 746c9a05452b3d2fe9564f41548a670dc14ed4ac Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 15:18:35 -0800 Subject: [PATCH 22/31] Refactor delegate vtable creation for custom types Updated DelegateVftbl and InvokeImpl methods to support custom sender and args types for delegate vtable generation. This enables more flexible vtable definitions beyond the previous fixed void* parameters. --- .../WellKnownTypeDefinitionFactory.cs | 43 ++++++++++++++++--- .../WellKnownTypeSignatureFactory.cs | 15 ++++--- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/WinRT.Interop.Generator/Factories/WellKnownTypeDefinitionFactory.cs b/src/WinRT.Interop.Generator/Factories/WellKnownTypeDefinitionFactory.cs index 0a007c5da..004602fed 100644 --- a/src/WinRT.Interop.Generator/Factories/WellKnownTypeDefinitionFactory.cs +++ b/src/WinRT.Interop.Generator/Factories/WellKnownTypeDefinitionFactory.cs @@ -96,13 +96,43 @@ public static TypeDefinition IInspectableVftbl(InteropReferences interopReferenc /// The instance to use. /// The module that will contain the type being created. /// The resulting instance. - /// This method always assumes the type will take two objects as input parameters. + /// + /// Unlike , + /// this overload just uses * as sender and args types, so it can be shared across reference types (for both types). + /// public static TypeDefinition DelegateVftbl(InteropReferences interopReferences, ModuleDefinition module) { - // We're declaring an 'internal struct' type - TypeDefinition vftblType = new( + return DelegateVftbl( ns: null, name: ""u8, + senderType: interopReferences.CorLibTypeFactory.Void.MakePointerType(), + argsType: interopReferences.CorLibTypeFactory.Void.MakePointerType(), + interopReferences: interopReferences, + module: module); + } + + /// + /// Creates a new type definition for the vtable of a type. + /// + /// The namespace for the type. + /// The type name. + /// The sender type for the vtable type. + /// The args type for the vtable type. + /// The instance to use. + /// The module that will contain the type being created. + /// The resulting instance. + public static TypeDefinition DelegateVftbl( + Utf8String? ns, + Utf8String name, + TypeSignature senderType, + TypeSignature argsType, + InteropReferences interopReferences, + ModuleDefinition module) + { + // We're declaring an 'internal struct' type + TypeDefinition vftblType = new( + ns: ns, + name: name, attributes: TypeAttributes.SequentialLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.ValueType.Import(module)); @@ -112,14 +142,17 @@ public static TypeDefinition DelegateVftbl(InteropReferences interopReferences, MethodSignature releaseType = WellKnownTypeSignatureFactory.ReleaseImpl(interopReferences); // Also get the 'Invoke' signature - MethodSignature invokeType = WellKnownTypeSignatureFactory.InvokeImpl(interopReferences); + MethodSignature invokeType = WellKnownTypeSignatureFactory.InvokeImpl( + senderType: senderType, + argsType: argsType, + interopReferences: interopReferences); // The vtable layout for 'IDelegate' looks like this: // // public delegate* unmanaged[MemberFunction] QueryInterface; // public delegate* unmanaged[MemberFunction] AddRef; // public delegate* unmanaged[MemberFunction] Release; - // public delegate* unmanaged[MemberFunction] Invoke; + // public delegate* unmanaged[MemberFunction], , HRESULT> Invoke; vftblType.Fields.Add(new FieldDefinition("QueryInterface"u8, FieldAttributes.Public, queryInterfaceType.Import(module).MakeFunctionPointerType())); vftblType.Fields.Add(new FieldDefinition("AddRef"u8, FieldAttributes.Public, addRefType.Import(module).MakeFunctionPointerType())); vftblType.Fields.Add(new FieldDefinition("Release"u8, FieldAttributes.Public, releaseType.Import(module).MakeFunctionPointerType())); diff --git a/src/WinRT.Interop.Generator/Factories/WellKnownTypeSignatureFactory.cs b/src/WinRT.Interop.Generator/Factories/WellKnownTypeSignatureFactory.cs index 18b55f6cf..d3b3acf21 100644 --- a/src/WinRT.Interop.Generator/Factories/WellKnownTypeSignatureFactory.cs +++ b/src/WinRT.Interop.Generator/Factories/WellKnownTypeSignatureFactory.cs @@ -243,13 +243,18 @@ public static MethodSignature get_UntypedRetVal(InteropReferences interopReferen } /// - /// Creates a type signature for the Invoke vtable entry for a delegate, taking objects for both parameters. + /// Creates a type signature for the Invoke vtable entry for a delegate. /// + /// The sender type for the vtable type. + /// The args type for the vtable type. /// The instance to use. /// The resulting instance. - public static MethodSignature InvokeImpl(InteropReferences interopReferences) + public static MethodSignature InvokeImpl( + TypeSignature senderType, + TypeSignature argsType, + InteropReferences interopReferences) { - // Signature for 'delegate* unmanaged[MemberFunction]' + // Signature for 'delegate* unmanaged[MemberFunction], , HRESULT>' return new( attributes: CallingConventionAttributes.Unmanaged, returnType: new CustomModifierTypeSignature( @@ -258,8 +263,8 @@ public static MethodSignature InvokeImpl(InteropReferences interopReferences) baseType: interopReferences.CorLibTypeFactory.Int32), parameterTypes: [ interopReferences.CorLibTypeFactory.Void.MakePointerType(), - interopReferences.CorLibTypeFactory.Void.MakePointerType(), - interopReferences.CorLibTypeFactory.Void.MakePointerType()]); + senderType, + argsType]); } /// From 1a0a7a4a563b88bcc9af5e76669e47e42075aebe Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 15:18:42 -0800 Subject: [PATCH 23/31] Rename sharedReadOnlyDictionaryType to sharedDictionaryType Refactored variable name from sharedReadOnlyDictionaryType to sharedDictionaryType for clarity and consistency in vtable type generation within InteropTypeDefinitionBuilder.IDictionary2. --- .../Builders/InteropTypeDefinitionBuilder.IDictionary2.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs index 931484484..a289fa335 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs @@ -135,14 +135,14 @@ static void GetOrCreateVftbl( } // Create a dummy signature just to generate the mangled name for the vtable type - TypeSignature sharedReadOnlyDictionaryType = interopReferences.IDictionary2.MakeGenericReferenceType( + TypeSignature sharedDictionaryType = interopReferences.IDictionary2.MakeGenericReferenceType( displayKeyType, displayValueType); // Construct a new specialized vtable type TypeDefinition newVftblType = WellKnownTypeDefinitionFactory.IDictionary2Vftbl( - ns: InteropUtf8NameFactory.TypeNamespace(sharedReadOnlyDictionaryType), - name: InteropUtf8NameFactory.TypeName(sharedReadOnlyDictionaryType, "Vftbl"), + ns: InteropUtf8NameFactory.TypeNamespace(sharedDictionaryType), + name: InteropUtf8NameFactory.TypeName(sharedDictionaryType, "Vftbl"), keyType: keyType, valueType: valueType, interopReferences: interopReferences, From d667fea2b86edb912a69a0fd578067eeaf7f0133 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 15:24:54 -0800 Subject: [PATCH 24/31] Add shared vtable type support for delegate interop Introduces logic to share vtable types for IDelegate interfaces when sender and args types are reference types, reducing redundant type generation. Adds new methods and state to track and reuse vtable types in InteropGeneratorEmitState, and updates delegate type generation to utilize this sharing mechanism. --- .../InteropTypeDefinitionBuilder.Delegate.cs | 127 +++++++++++++++++- .../Generation/InteropGenerator.Emit.cs | 8 ++ .../Generation/InteropGeneratorEmitState.cs | 31 +++++ 3 files changed, 165 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index 7cb24f3a2..b80762cc6 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -66,6 +66,125 @@ public static void IIDs( out get_ReferenceIidMethod); } + /// + /// Creates a new type definition for the vtable for an IDelegate interface. + /// + /// The for the type. + /// The instance to use. + /// The instance to use. + /// The emit state for this invocation. + /// The interop module being built. + /// The resulting vtable type. + public static void Vftbl( + GenericInstanceTypeSignature delegateType, + InteropDefinitions interopDefinitions, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState, + ModuleDefinition module, + out TypeDefinition vftblType) + { + MemberReference delegateInvokeMethod = interopReferences.DelegateInvoke(delegateType, module); + + // Prepare the sender and arguments types (same as for the 'Impl' type below) + TypeSignature senderType = ((MethodSignature)delegateInvokeMethod.Signature!).ParameterTypes[0]; + TypeSignature argsType = ((MethodSignature)delegateInvokeMethod.Signature!).ParameterTypes[1]; + + bool isSenderReferenceType = senderType.HasReferenceAbiType(interopReferences); + bool isArgsReferenceType = argsType.HasReferenceAbiType(interopReferences); + + // We can share the vtable type for 'void*' when both sender and args types are reference types + if (isSenderReferenceType && isArgsReferenceType) + { + vftblType = interopDefinitions.DelegateVftbl; + + return; + } + + // If both the sender and the args types are not reference types, we can't possibly share + // the vtable type. So in this case, we just always construct a specialized new type. + if (!isSenderReferenceType && !isArgsReferenceType) + { + vftblType = WellKnownTypeDefinitionFactory.DelegateVftbl( + ns: InteropUtf8NameFactory.TypeNamespace(delegateType), + name: InteropUtf8NameFactory.TypeName(delegateType, "Vftbl"), + senderType: senderType.GetAbiType(interopReferences), + argsType: argsType.GetAbiType(interopReferences), + interopReferences: interopReferences, + module: module); + + module.TopLevelTypes.Add(vftblType); + + return; + } + + // Helper to create vtable types that can be shared between multiple delegate types + static void GetOrCreateVftbl( + TypeSignature senderType, + TypeSignature argsType, + TypeSignature displaySenderType, + TypeSignature displayArgsType, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState, + ModuleDefinition module, + out TypeDefinition vftblType) + { + // If we already have a vtable type for this pair, reuse that + if (emitState.TryGetDelegateVftblType(senderType, argsType, out vftblType!)) + { + return; + } + + // Create a dummy signature just to generate the mangled name for the vtable type + TypeSignature sharedEventHandlerType = interopReferences.EventHandler2.MakeGenericReferenceType( + displaySenderType, + displayArgsType); + + // Construct a new specialized vtable type + TypeDefinition newVftblType = WellKnownTypeDefinitionFactory.DelegateVftbl( + ns: InteropUtf8NameFactory.TypeNamespace(sharedEventHandlerType), + name: InteropUtf8NameFactory.TypeName(sharedEventHandlerType, "Vftbl"), + senderType: senderType, + argsType: argsType, + interopReferences: interopReferences, + module: module); + + // Go through the lookup so that we can reuse the vtable later + vftblType = emitState.GetOrAddDelegateVftblType(senderType, argsType, newVftblType); + + // If we won the race and this is the vtable type that was just created, we can add it to the module + if (vftblType == newVftblType) + { + module.TopLevelTypes.Add(newVftblType); + } + } + + // Get or create a shared vtable where the reference type is replaced with just 'void*' + if (isSenderReferenceType) + { + GetOrCreateVftbl( + senderType: interopReferences.CorLibTypeFactory.Void.MakePointerType(), + argsType: argsType.GetAbiType(interopReferences), + displaySenderType: interopReferences.CorLibTypeFactory.Object, + displayArgsType: argsType, + interopReferences: interopReferences, + emitState: emitState, + module: module, + out vftblType); + } + else + { + GetOrCreateVftbl( + senderType: senderType.GetAbiType(interopReferences), + argsType: interopReferences.CorLibTypeFactory.Void.MakePointerType(), + displaySenderType: senderType, + displayArgsType: interopReferences.CorLibTypeFactory.Object, + interopReferences: interopReferences, + emitState: emitState, + module: module, + out vftblType); + } + } + /// /// Creates a new type definition for the implementation of the vtable for an 'IDelegate' interface. /// @@ -442,6 +561,12 @@ public static void NativeDelegateType( nativeDelegateType.Methods.Add(invokeMethod); + // Prepare the 'Invoke' signature + MethodSignature invokeSignature = WellKnownTypeSignatureFactory.InvokeImpl( + senderType: senderType.GetAbiType(interopReferences), + argsType: argsType.GetAbiType(interopReferences), + interopReferences: interopReferences); + // Import 'WindowsRuntimeObjectReferenceValue', compute it just once TypeSignature windowsRuntimeObjectReferenceValueType = interopReferences.WindowsRuntimeObjectReferenceValue .Import(module) @@ -490,7 +615,7 @@ public static void NativeDelegateType( { Ldloc_1 }, { Ldind_I }, { Ldfld, interopDefinitions.DelegateVftbl.Fields[3] }, - { Calli, WellKnownTypeSignatureFactory.InvokeImpl(interopReferences).Import(module).MakeStandAloneSignature() }, + { Calli, invokeSignature.Import(module).MakeStandAloneSignature() }, { Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module) }, { Leave_S, ret.CreateLabel() }, diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index a939fc19f..2881f4e8b 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -272,6 +272,14 @@ private static void DefineGenericDelegateTypes( get_IidMethod: out MethodDefinition get_IidMethod, get_ReferenceIidMethod: out MethodDefinition get_ReferenceIidMethod); + InteropTypeDefinitionBuilder.Delegate.Vftbl( + delegateType: typeSignature, + interopDefinitions: interopDefinitions, + interopReferences: interopReferences, + emitState: emitState, + module: module, + vftblType: out TypeDefinition vftblType); + InteropTypeDefinitionBuilder.Delegate.NativeDelegateType( delegateType: typeSignature, interopDefinitions: interopDefinitions, diff --git a/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs b/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs index 960245150..96e09161c 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGeneratorEmitState.cs @@ -40,6 +40,11 @@ internal sealed class InteropGeneratorEmitState /// private readonly ConcurrentDictionary<(TypeSignature Key, TypeSignature Value), TypeDefinition> _mapVftblTypes = new(SignatureComparer.IgnoreVersion.MakeValueTupleComparer()); + /// + /// A map to allow reusing vtable types for applicable IDelegate interfaces. + /// + private readonly ConcurrentDictionary<(TypeSignature Sender, TypeSignature Args), TypeDefinition> _delegateVftblTypes = new(SignatureComparer.IgnoreVersion.MakeValueTupleComparer()); + /// /// Indicates whether the current state is readonly. /// @@ -240,6 +245,32 @@ public TypeDefinition GetOrAddIMap2VftblType(TypeSignature keyType, TypeSignatur return _mapVftblTypes.GetOrAdd((keyType, valueType), vftblType); } + /// + /// Tries to get a previously registered vtable type for an IDelegate interface. + /// + /// The sender type. + /// The args type. + /// The resulting vtable type, if present. + /// Whether was successfully retrieved. + public bool TryGetDelegateVftblType(TypeSignature senderType, TypeSignature argsType, [NotNullWhen(true)] out TypeDefinition? vftblType) + { + return _delegateVftblTypes.TryGetValue((senderType, argsType), out vftblType); + } + + /// + /// Gets or adds a vtable type for an IDelegate interface. + /// + /// The key type. + /// The value type. + /// The created vtable type for . + /// The vtable type that should be used. + public TypeDefinition GetOrAddDelegateVftblType(TypeSignature senderType, TypeSignature argsType, TypeDefinition vftblType) + { + ThrowIfReadOnly(); + + return _delegateVftblTypes.GetOrAdd((senderType, argsType), vftblType); + } + /// /// Marks the current state as readonly. /// From fbb1ce99971328f67a98f89d0d0ead84ddd3c35c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 15:26:50 -0800 Subject: [PATCH 25/31] Pass vftblType to Delegate.ImplType method Adds the vftblType parameter to InteropTypeDefinitionBuilder.Delegate.ImplType and updates its usage in InteropGenerator.Emit. This change clarifies the source of the vftbl type and improves method signature accuracy. --- .../Builders/InteropTypeDefinitionBuilder.Delegate.cs | 4 +++- .../Generation/InteropGenerator.Emit.cs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index b80762cc6..fd76cf46c 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -189,6 +189,7 @@ static void GetOrCreateVftbl( /// Creates a new type definition for the implementation of the vtable for an 'IDelegate' interface. /// /// The for the type. + /// The type returned by . /// The instance to use. /// The instance to use. /// The emit state for this invocation. @@ -196,6 +197,7 @@ static void GetOrCreateVftbl( /// The resulting implementation type. public static void ImplType( GenericInstanceTypeSignature delegateType, + TypeDefinition vftblType, InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, @@ -291,7 +293,7 @@ public static void ImplType( interfaceType: ComInterfaceType.InterfaceIsIUnknown, ns: InteropUtf8NameFactory.TypeNamespace(delegateType), name: InteropUtf8NameFactory.TypeName(delegateType, "Impl"), - vftblType: interopDefinitions.DelegateVftbl, + vftblType: vftblType, interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index 2881f4e8b..f7c17fd92 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -308,6 +308,7 @@ private static void DefineGenericDelegateTypes( InteropTypeDefinitionBuilder.Delegate.ImplType( delegateType: typeSignature, + vftblType: vftblType, interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, From 401c4ddcd263abac265307fe890d63584253b22d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 19:02:20 -0800 Subject: [PATCH 26/31] Clarify XML doc references to AsmResolver.DotNet.TypeReference Updated XML documentation comments to specify AsmResolver.DotNet.TypeReference instead of the more generic TypeReference, improving clarity for consumers of the InteropReferences class. --- .../References/InteropReferences.cs | 417 ++++++++++-------- 1 file changed, 223 insertions(+), 194 deletions(-) diff --git a/src/WinRT.Interop.Generator/References/InteropReferences.cs b/src/WinRT.Interop.Generator/References/InteropReferences.cs index 348103964..86c27fea9 100644 --- a/src/WinRT.Interop.Generator/References/InteropReferences.cs +++ b/src/WinRT.Interop.Generator/References/InteropReferences.cs @@ -89,27 +89,27 @@ public InteropReferences( publicKeyOrToken: WellKnownPublicKeyTokens.SystemMemory); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Attribute => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Attribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference AttributeTargets => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "AttributeTargets"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference AttributeUsageAttribute => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "AttributeUsageAttribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference TypeMapAttribute1 => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices"u8, "TypeMapAttribute`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference GuidAttribute => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices"u8, "GuidAttribute"u8); @@ -119,7 +119,7 @@ public InteropReferences( public GenericInstanceTypeSignature TypeMapAttributeWindowsRuntimeComWrappersTypeMapGroup => field ??= TypeMapAttribute1.MakeGenericReferenceType(WindowsRuntimeComWrappersTypeMapGroup.ToReferenceTypeSignature()); /// - /// Gets the for . + /// Gets the for . /// public TypeReference TypeMapAssociationAttribute1 => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices"u8, "TypeMapAssociationAttribute`1"u8); @@ -129,47 +129,47 @@ public InteropReferences( public GenericInstanceTypeSignature TypeMapAssociationAttributeDynamicInterfaceCastableImplementationTypeMapGroup => field ??= TypeMapAttribute1.MakeGenericReferenceType(DynamicInterfaceCastableImplementationTypeMapGroup.ToReferenceTypeSignature()); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Array => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Array"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Nullable1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Nullable`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Type => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Type"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference RuntimeTypeHandle => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "RuntimeTypeHandle"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Delegate => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Delegate"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ValueType => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "ValueType"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference FlagsAttribute => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "FlagsAttribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Span1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Span`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ReadOnlySpan1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "ReadOnlySpan`1"u8); @@ -194,827 +194,832 @@ public InteropReferences( public GenericInstanceTypeSignature ReadOnlySpanInt32 => field ??= ReadOnlySpan1.MakeGenericValueType(_corLibTypeFactory.Int32); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Func3 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Func`3"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Exception => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Exception"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference NotSupportedException => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "NotSupportedException"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Guid => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Guid"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference EventHandler => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "EventHandler"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference EventHandler1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "EventHandler`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference EventHandler2 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "EventHandler`2"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IDisposable => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "IDisposable"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference TimeSpan => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "TimeSpan"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference DateTimeOffset => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "DateTimeOffset"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IServiceProvider => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "IServiceProvider"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ICommand => field ??= SystemObjectModel.CreateTypeReference("System.Windows.Input"u8, "ICommand"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference INotifyCollectionChanged => field ??= SystemObjectModel.CreateTypeReference("System.Collections.Specialized"u8, "INotifyCollectionChanged"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference INotifyDataErrorInfo => field ??= SystemObjectModel.CreateTypeReference("System.ComponentModel"u8, "INotifyDataErrorInfo"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference INotifyPropertyChanged => field ??= SystemObjectModel.CreateTypeReference("System.ComponentModel"u8, "INotifyPropertyChanged"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IEnumerator => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections"u8, "IEnumerator"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IEnumerator1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "IEnumerator`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IEnumerable => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections"u8, "IEnumerable"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IEnumerable1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "IEnumerable`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ICollection1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "ICollection`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IReadOnlyCollection1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "IReadOnlyCollection`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IList => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections"u8, "IList"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IList1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "IList`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IReadOnlyList1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "IReadOnlyList`1"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IDictionary2 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "IDictionary`2"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IReadOnlyDictionary2 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "IReadOnlyDictionary`2"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference KeyValuePair => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "KeyValuePair"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference KeyValuePair2 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Collections.Generic"u8, "KeyValuePair`2"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference NotifyCollectionChangedEventHandler => field ??= SystemObjectModel.CreateTypeReference("System.Collections.Specialized"u8, "NotifyCollectionChangedEventHandler"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference NotifyCollectionChangedEventArgs => field ??= SystemObjectModel.CreateTypeReference("System.Collections.Specialized"u8, "NotifyCollectionChangedEventArgs"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference PropertyChangedEventHandler => field ??= SystemObjectModel.CreateTypeReference("System.ComponentModel"u8, "PropertyChangedEventHandler"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference PropertyChangedEventArgs => field ??= SystemObjectModel.CreateTypeReference("System.ComponentModel"u8, "PropertyChangedEventArgs"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference MemoryExtensions => field ??= SystemMemory.CreateTypeReference("System"u8, "MemoryExtensions"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference Interlocked => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Threading"u8, "Interlocked"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference MemoryMarshal => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Runtime.InteropServices"u8, "MemoryMarshal"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ComWrappers => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices"u8, "ComWrappers"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ComInterfaceDispatch => field ??= ComWrappers.CreateTypeReference("ComInterfaceDispatch"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ComInterfaceEntry => field ??= ComWrappers.CreateTypeReference("ComInterfaceEntry"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference CreateComInterfaceFlags => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices"u8, "CreateComInterfaceFlags"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference CreatedWrapperFlags => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices"u8, "CreatedWrapperFlags"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference InAttribute => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Runtime.InteropServices"u8, "InAttribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference DynamicInterfaceCastableImplementationAttribute => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices"u8, "DynamicInterfaceCastableImplementationAttribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IUnknownDerivedAttribute2 => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices.Marshalling"u8, "IUnknownDerivedAttribute`2"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IIUnknownInterfaceType => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices.Marshalling"u8, "IIUnknownInterfaceType"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IsVolatile => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Runtime.CompilerServices"u8, "IsVolatile"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference IsReadOnlyAttribute => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Runtime.CompilerServices"u8, "IsReadOnlyAttribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference FixedAddressValueTypeAttribute => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Runtime.CompilerServices"u8, "FixedAddressValueTypeAttribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ScopedRefAttribute => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Runtime.CompilerServices"u8, "ScopedRefAttribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference CallConvMemberFunction => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Runtime.CompilerServices"u8, "CallConvMemberFunction"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference ConditionalWeakTable2 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System.Runtime.CompilerServices"u8, "ConditionalWeakTable`2"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference UnmanagedCallersOnlyAttribute => field ??= SystemRuntimeInteropServices.CreateTypeReference("System.Runtime.InteropServices"u8, "UnmanagedCallersOnlyAttribute"u8); /// - /// Gets the for ABI.System.Type. + /// Gets the for ABI.System.Type. /// public TypeReference AbiType => field ??= _windowsRuntimeModule.CreateTypeReference("ABI.System"u8, "Type"u8); /// - /// Gets the for ABI.System.Exception. + /// Gets the for ABI.System.Exception. /// public TypeReference AbiException => field ??= _windowsRuntimeModule.CreateTypeReference("ABI.System"u8, "Exception"u8); /// - /// Gets the for ABI.System.TimeSpan. + /// Gets the for ABI.System.TimeSpan. /// public TypeReference AbiTimeSpan => field ??= _windowsRuntimeModule.CreateTypeReference("ABI.System"u8, "TimeSpan"u8); /// - /// Gets the for ABI.System.DateTimeOffset. + /// Gets the for ABI.System.DateTimeOffset. /// public TypeReference AbiDateTimeOffset => field ??= _windowsRuntimeModule.CreateTypeReference("ABI.System"u8, "DateTimeOffset"u8); /// - /// Gets the for ABI.System.TypeMarshaller. + /// Gets the for ABI.System.TypeMarshaller. /// public TypeReference TypeMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("ABI.System"u8, "TypeMarshaller"u8); /// - /// Gets the for ABI.System.TypeMarshaller. + /// Gets the for ABI.System.TypeMarshaller. /// public TypeReference ExceptionMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("ABI.System"u8, "ExceptionMarshaller"u8); /// - /// Gets the for ABI.System.TimeSpanMarshaller. + /// Gets the for ABI.System.TimeSpanMarshaller. /// public TypeReference TimeSpanMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("ABI.System"u8, "TimeSpanMarshaller"u8); /// - /// Gets the for ABI.System.DateTimeOffsetMarshaller. + /// Gets the for ABI.System.DateTimeOffsetMarshaller. /// public TypeReference DateTimeOffsetMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("ABI.System"u8, "DateTimeOffsetMarshaller"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeClassNameAttribute. + /// Gets the for WindowsRuntime.WindowsRuntimeClassNameAttribute. /// public TypeReference WindowsRuntimeClassNameAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeClassNameAttribute"u8); /// - /// Gets the for . + /// Gets the for . /// public TypeReference WindowsRuntimeDefaultInterfaceAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeDefaultInterfaceAttribute"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeMetadataAttribute. + /// Gets the for WindowsRuntime.WindowsRuntimeMetadataAttribute. /// public TypeReference WindowsRuntimeMetadataAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeMetadataAttribute"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeManagedOnlyTypeAttribute. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeManagedOnlyTypeAttribute. /// public TypeReference WindowsRuntimeManagedOnlyTypeAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeManagedOnlyTypeAttribute"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeComWrappersTypeMapGroup. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeComWrappersTypeMapGroup. /// public TypeReference WindowsRuntimeComWrappersTypeMapGroup => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeComWrappersTypeMapGroup"u8); /// - /// Gets the for WindowsRuntime.InteropServices.DynamicInterfaceCastableImplementationTypeMapGroup. + /// Gets the for WindowsRuntime.InteropServices.DynamicInterfaceCastableImplementationTypeMapGroup. /// public TypeReference DynamicInterfaceCastableImplementationTypeMapGroup => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "DynamicInterfaceCastableImplementationTypeMapGroup"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WellKnownInterfaceIIDs. + /// Gets the for WindowsRuntime.InteropServices.WellKnownInterfaceIIDs. /// public TypeReference WellKnownInterfaceIIDs => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WellKnownInterfaceIIDs"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IUnknownImpl. + /// Gets the for WindowsRuntime.InteropServices.IUnknownImpl. /// public TypeReference IUnknownImpl => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IUnknownImpl"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IInspectableImpl. + /// Gets the for WindowsRuntime.InteropServices.IInspectableImpl. /// public TypeReference IInspectableImpl => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IInspectableImpl"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IPropertyValueImpl. + /// Gets the for WindowsRuntime.InteropServices.IPropertyValueImpl. /// public TypeReference IPropertyValueImpl => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IPropertyValueImpl"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IStringableImpl. + /// Gets the for WindowsRuntime.InteropServices.IStringableImpl. /// public TypeReference IStringableImpl => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IStringableImpl"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IMarshalImpl. + /// Gets the for WindowsRuntime.InteropServices.IMarshalImpl. /// public TypeReference IMarshalImpl => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IMarshalImpl"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IWeakReferenceSourceImpl. + /// Gets the for WindowsRuntime.InteropServices.IWeakReferenceSourceImpl. /// public TypeReference IWeakReferenceSourceImpl => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IWeakReferenceSourceImpl"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IAgileObjectImpl. + /// Gets the for WindowsRuntime.InteropServices.IAgileObjectImpl. /// public TypeReference IAgileObjectImpl => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IAgileObjectImpl"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IAsyncActionWithProgressMethods. + /// Gets the for WindowsRuntime.InteropServices.IAsyncActionWithProgressMethods. /// public TypeReference IAsyncActionWithProgressMethods => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IAsyncActionWithProgressMethods"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IAsyncActionWithProgressMethodsImpl<TProgress>. + /// Gets the for WindowsRuntime.InteropServices.IAsyncActionWithProgressMethodsImpl<TProgress>. /// public TypeReference IAsyncActionWithProgressMethodsImpl1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IAsyncActionWithProgressMethodsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IAsyncOperationMethodsImpl<TResult>. + /// Gets the for WindowsRuntime.InteropServices.IAsyncOperationMethodsImpl<TResult>. /// public TypeReference IAsyncOperationMethodsImpl1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IAsyncOperationMethodsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IAsyncOperationWithProgressMethodsImpl<TResult, TProgress>. + /// Gets the for WindowsRuntime.InteropServices.IAsyncOperationWithProgressMethodsImpl<TResult, TProgress>. /// public TypeReference IAsyncOperationWithProgressMethodsImpl2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IAsyncOperationWithProgressMethodsImpl`2"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IIterableMethodsImpl<T>. + /// Gets the for WindowsRuntime.InteropServices.IIterableMethodsImpl<T>. /// public TypeReference IIterableMethodsImpl1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IIterableMethodsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IIteratorMethods. + /// Gets the for WindowsRuntime.InteropServices.IIteratorMethods. /// public TypeReference IIteratorMethods => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IIteratorMethods"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IIteratorMethodsImpl<T>. + /// Gets the for WindowsRuntime.InteropServices.IIteratorMethodsImpl<T>. /// public TypeReference IIteratorMethodsImpl1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IIteratorMethodsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IEnumeratorAdapter<T>. + /// Gets the for WindowsRuntime.InteropServices.IEnumeratorAdapter<T>. /// public TypeReference IEnumeratorAdapter1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IEnumeratorAdapter`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsImpl<T>. + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsImpl<T>. /// public TypeReference IVectorMethodsImpl1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsImpl<T>. + /// Gets the for WindowsRuntime.InteropServices.IVectorMethodsImpl<T>. /// public TypeReference IVectorMethods1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorMethodsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IVectorViewMethodsImpl<T>. + /// Gets the for WindowsRuntime.InteropServices.IVectorViewMethodsImpl<T>. /// public TypeReference IVectorViewMethods1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IVectorViewMethodsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IMapMethodsImpl<K, V>. + /// Gets the for WindowsRuntime.InteropServices.IMapMethodsImpl<K, V>. /// public TypeReference IMapMethodsImpl2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IMapMethodsImpl`2"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IMapViewMethodsImpl<K, V>. + /// Gets the for WindowsRuntime.InteropServices.IMapViewMethodsImpl<K, V>. /// public TypeReference IMapViewMethodsImpl2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IMapViewMethodsImpl`2"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IObservableVectorMethodsImpl<T>. + /// Gets the for WindowsRuntime.InteropServices.IObservableVectorMethodsImpl<T>. /// public TypeReference IObservableVectorMethodsImpl1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IObservableVectorMethodsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IObservableMapMethodsImpl<TKey, TValue>. + /// Gets the for WindowsRuntime.InteropServices.IObservableMapMethodsImpl<TKey, TValue>. /// public TypeReference IObservableMapMethodsImpl2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IObservableMapMethodsImpl`2"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IMapChangedEventArgsImpl<K>. + /// Gets the for WindowsRuntime.InteropServices.IMapChangedEventArgsImpl<K>. /// public TypeReference IMapChangedEventArgsImpl1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IMapChangedEventArgsImpl`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IListMethods. + /// Gets the for WindowsRuntime.InteropServices.IListMethods. /// public TypeReference IListMethods => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IListMethods"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IReadOnlyListMethods. + /// Gets the for WindowsRuntime.InteropServices.IReadOnlyListMethods. /// public TypeReference IReadOnlyListMethods => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IReadOnlyListMethods"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IListMethods<T>. + /// Gets the for WindowsRuntime.InteropServices.IListMethods<T>. /// public TypeReference IListMethods1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IListMethods`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IReadOnlyListMethods<T>. + /// Gets the for WindowsRuntime.InteropServices.IReadOnlyListMethods<T>. /// public TypeReference IReadOnlyListMethods1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IReadOnlyListMethods`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IDictionaryMethods. + /// Gets the for WindowsRuntime.InteropServices.IDictionaryMethods. /// public TypeReference IDictionaryMethods => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IDictionaryMethods"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IDictionaryMethods<TKey, TValue>. + /// Gets the for WindowsRuntime.InteropServices.IDictionaryMethods<TKey, TValue>. /// public TypeReference IDictionaryMethods2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IDictionaryMethods`2"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IReadOnlyDictionaryMethods. + /// Gets the for WindowsRuntime.InteropServices.IReadOnlyDictionaryMethods. /// public TypeReference IReadOnlyDictionaryMethods => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IReadOnlyDictionaryMethods"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IReadOnlyDictionaryMethods<TKey, TValue>. + /// Gets the for WindowsRuntime.InteropServices.IReadOnlyDictionaryMethods<TKey, TValue>. /// public TypeReference IReadOnlyDictionaryMethods2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IReadOnlyDictionaryMethods`2"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IMapChangedEventArgsMethods. + /// Gets the for WindowsRuntime.InteropServices.IMapChangedEventArgsMethods. /// public TypeReference IMapChangedEventArgsMethods => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IMapChangedEventArgsMethods"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeObject. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeObject. /// public TypeReference WindowsRuntimeObject => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeObject"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeAsyncActionWithProgress<T, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeAsyncActionWithProgress<T, ...>. /// public TypeReference WindowsRuntimeAsyncActionWithProgress2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeAsyncActionWithProgress`2"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeAsyncOperation<T, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeAsyncOperation<T, ...>. /// public TypeReference WindowsRuntimeAsyncOperation2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeAsyncOperation`2"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeAsyncOperationWithProgress<T, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeAsyncOperationWithProgress<T, ...>. /// public TypeReference WindowsRuntimeAsyncOperationWithProgress3 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeAsyncOperationWithProgress`3"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeEnumerator<T, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeEnumerator<T, ...>. /// public TypeReference WindowsRuntimeEnumerator2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeEnumerator`2"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeEnumerable<T, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeEnumerable<T, ...>. /// public TypeReference WindowsRuntimeEnumerable2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeEnumerable`2"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeList<T, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeList<T, ...>. /// public TypeReference WindowsRuntimeList4 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeList`4"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeReadOnlyList<T, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeReadOnlyList<T, ...>. /// public TypeReference WindowsRuntimeReadOnlyList4 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeReadOnlyList`4"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeDictionary<TKey, TValue, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeDictionary<TKey, TValue, ...>. /// public TypeReference WindowsRuntimeDictionary5 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeDictionary`5"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeReadOnlyDictionary<TKey, TValue, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeReadOnlyDictionary<TKey, TValue, ...>. /// public TypeReference WindowsRuntimeReadOnlyDictionary5 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeReadOnlyDictionary`5"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeObservableVector<T, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeObservableVector<T, ...>. /// public TypeReference WindowsRuntimeObservableVector6 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeObservableVector`6"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeObservableMap<TKey, TValue, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeObservableMap<TKey, TValue, ...>. /// public TypeReference WindowsRuntimeObservableMap7 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeObservableMap`7"u8); /// - /// Gets the for WindowsRuntime.WindowsRuntimeMapChangedEventArgs<TKey, ...>. + /// Gets the for WindowsRuntime.WindowsRuntimeMapChangedEventArgs<TKey, ...>. /// public TypeReference WindowsRuntimeMapChangedEventArgs2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeMapChangedEventArgs`2"u8); /// - /// Gets the for WindowsRuntime.DictionaryKeyCollection2<TKey, TValue>. + /// Gets the for WindowsRuntime.DictionaryKeyCollection2<TKey, TValue>. /// public TypeReference DictionaryKeyCollection2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "DictionaryKeyCollection`2"u8); /// - /// Gets the for WindowsRuntime.DictionaryValueCollection2<TKey, TValue>. + /// Gets the for WindowsRuntime.DictionaryValueCollection2<TKey, TValue>. /// public TypeReference DictionaryValueCollection2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "DictionaryValueCollection`2"u8); /// - /// Gets the for WindowsRuntime.ReadOnlyDictionaryKeyCollection2<TKey, TValue>. + /// Gets the for WindowsRuntime.ReadOnlyDictionaryKeyCollection2<TKey, TValue>. /// public TypeReference ReadOnlyDictionaryKeyCollection2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "ReadOnlyDictionaryKeyCollection`2"u8); /// - /// Gets the for WindowsRuntime.ReadOnlyDictionaryValueCollection2<TKey, TValue>. + /// Gets the for WindowsRuntime.ReadOnlyDictionaryValueCollection2<TKey, TValue>. /// public TypeReference ReadOnlyDictionaryValueCollection2 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "ReadOnlyDictionaryValueCollection`2"u8); /// - /// Gets the for WindowsRuntime.InteropServices.BindableIReadOnlyListAdapter. + /// Gets the for WindowsRuntime.InteropServices.BindableIReadOnlyListAdapter. /// public TypeReference BindableIReadOnlyListAdapter => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "BindableIReadOnlyListAdapter"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeInterface. + /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeInterface. /// public TypeReference IWindowsRuntimeInterface => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IWindowsRuntimeInterface"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeObjectComWrappersCallback. + /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeObjectComWrappersCallback. /// public TypeReference IWindowsRuntimeObjectComWrappersCallback => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IWindowsRuntimeObjectComWrappersCallback"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeUnsealedObjectComWrappersCallback. + /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeUnsealedObjectComWrappersCallback. /// public TypeReference IWindowsRuntimeUnsealedObjectComWrappersCallback => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IWindowsRuntimeUnsealedObjectComWrappersCallback"u8); /// - /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeArrayComWrappersCallback. + /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeArrayComWrappersCallback. /// public TypeReference IWindowsRuntimeArrayComWrappersCallback => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "IWindowsRuntimeArrayComWrappersCallback"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeComWrappersMarshallerAttribute. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeComWrappersMarshallerAttribute. /// public TypeReference WindowsRuntimeComWrappersMarshallerAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeComWrappersMarshallerAttribute"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeObjectReference. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeObjectReference. /// public TypeReference WindowsRuntimeObjectReference => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeObjectReference"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeObjectReferenceValue. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeObjectReferenceValue. /// public TypeReference WindowsRuntimeObjectReferenceValue => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeObjectReferenceValue"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeComWrappersMarshal. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeComWrappersMarshal. /// public TypeReference WindowsRuntimeComWrappersMarshal => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeComWrappersMarshal"u8); /// - /// Gets the for WindowsRuntime.InteropServices.Marshalling.WindowsRuntimeUnknownMarshaller. + /// Gets the for WindowsRuntime.InteropServices.Marshalling.WindowsRuntimeUnknownMarshaller. /// public TypeReference WindowsRuntimeUnknownMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "WindowsRuntimeUnknownMarshaller"u8); /// - /// Gets the for WindowsRuntime.InteropServices.Marshalling.WindowsRuntimeObjectMarshaller. + /// Gets the for WindowsRuntime.InteropServices.Marshalling.WindowsRuntimeObjectMarshaller. /// public TypeReference WindowsRuntimeObjectMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "WindowsRuntimeObjectMarshaller"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeUnsealedObjectMarshaller. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeUnsealedObjectMarshaller. /// public TypeReference WindowsRuntimeUnsealedObjectMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "WindowsRuntimeUnsealedObjectMarshaller"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeInterfaceMarshaller<T>. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeInterfaceMarshaller<T>. /// public TypeReference WindowsRuntimeInterfaceMarshaller1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "WindowsRuntimeInterfaceMarshaller`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeDelegateMarshaller. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeDelegateMarshaller. /// public TypeReference WindowsRuntimeDelegateMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "WindowsRuntimeDelegateMarshaller"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeArrayMarshaller. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeArrayMarshaller. /// public TypeReference WindowsRuntimeArrayMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "WindowsRuntimeArrayMarshaller"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeValueTypeMarshaller. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeValueTypeMarshaller. /// public TypeReference WindowsRuntimeValueTypeMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "WindowsRuntimeValueTypeMarshaller"u8); /// - /// Gets the for WindowsRuntime.InteropServices.HStringMarshaller. + /// Gets the for WindowsRuntime.InteropServices.Marshalling.TypeReference. + /// + public TypeReference TypeReference => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "TypeReference"u8); + + /// + /// Gets the for WindowsRuntime.InteropServices.HStringMarshaller. /// public TypeReference HStringMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "HStringMarshaller"u8); /// - /// Gets the for WindowsRuntime.InteropServices.RestrictedErrorInfo. + /// Gets the for WindowsRuntime.InteropServices.RestrictedErrorInfo. /// public TypeReference RestrictedErrorInfo => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "RestrictedErrorInfo"u8); /// - /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeArrayHelpers. + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeArrayHelpers. /// public TypeReference WindowsRuntimeArrayHelpers => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeArrayHelpers"u8); /// - /// Gets the for WindowsRuntime.InteropServices.Marshalling.RestrictedErrorInfoExceptionMarshaller. + /// Gets the for WindowsRuntime.InteropServices.Marshalling.RestrictedErrorInfoExceptionMarshaller. /// public TypeReference RestrictedErrorInfoExceptionMarshaller => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "RestrictedErrorInfoExceptionMarshaller"u8); /// - /// Gets the for WindowsRuntime.InteropServices.EventRegistrationToken. + /// Gets the for WindowsRuntime.InteropServices.EventRegistrationToken. /// public TypeReference EventRegistrationToken => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "EventRegistrationToken"u8); /// - /// Gets the for WindowsRuntime.InteropServices.EventRegistrationTokenTable<T>. + /// Gets the for WindowsRuntime.InteropServices.EventRegistrationTokenTable<T>. /// public TypeReference EventRegistrationTokenTable1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "EventRegistrationTokenTable`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.EventSource<T>. + /// Gets the for WindowsRuntime.InteropServices.EventSource<T>. /// public TypeReference EventSource1 => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "EventSource`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.EventHandlerEventSource<TEventArgs>. + /// Gets the for WindowsRuntime.InteropServices.EventHandlerEventSource<TEventArgs>. /// public TypeReference EventHandler1EventSource => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "EventHandlerEventSource`1"u8); /// - /// Gets the for WindowsRuntime.InteropServices.EventHandlerEventSource<TSender, TEventArgs>. + /// Gets the for WindowsRuntime.InteropServices.EventHandlerEventSource<TSender, TEventArgs>. /// public TypeReference EventHandler2EventSource => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "EventHandlerEventSource`2"u8); /// - /// Gets the for Windows.Foundation.Collections.IObservableVector<T>. + /// Gets the for Windows.Foundation.Collections.IObservableVector<T>. /// public TypeReference IObservableVector1 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation.Collections"u8, "IObservableVector`1"u8); /// - /// Gets the for Windows.Foundation.Collections.IObservableMap<K, V>. + /// Gets the for Windows.Foundation.Collections.IObservableMap<K, V>. /// public TypeReference IObservableMap2 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation.Collections"u8, "IObservableMap`2"u8); /// - /// Gets the for Windows.Foundation.Collections.IMapChangedEventArgs<K>. + /// Gets the for Windows.Foundation.Collections.IMapChangedEventArgs<K>. /// public TypeReference IMapChangedEventArgs1 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation.Collections"u8, "IMapChangedEventArgs`1"u8); /// - /// Gets the for Windows.Foundation.Collections.IVectorChangedEventArgs<T>. + /// Gets the for Windows.Foundation.Collections.IVectorChangedEventArgs<T>. /// public TypeReference IVectorChangedEventArgs => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation.Collections"u8, "IVectorChangedEventArgs"u8); /// - /// Gets the for Windows.Foundation.Collections.CollectionChange. + /// Gets the for Windows.Foundation.Collections.CollectionChange. /// public TypeReference CollectionChange => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation.Collections"u8, "CollectionChange"u8); /// - /// Gets the for Windows.Foundation.Collections.VectorChangedEventHandler<T>. + /// Gets the for Windows.Foundation.Collections.VectorChangedEventHandler<T>. /// public TypeReference VectorChangedEventHandler1 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation.Collections"u8, "VectorChangedEventHandler`1"u8); /// - /// Gets the for the event source type for . + /// Gets the for the event source type for . /// public TypeReference VectorChangedEventHandler1EventSource => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "VectorChangedEventHandlerEventSource`1"u8); /// - /// Gets the for Windows.Foundation.Collections.MapChangedEventHandler<K, V>. + /// Gets the for Windows.Foundation.Collections.MapChangedEventHandler<K, V>. /// public TypeReference MapChangedEventHandler2 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation.Collections"u8, "MapChangedEventHandler`2"u8); /// - /// Gets the for the event source type for . + /// Gets the for the event source type for . /// public TypeReference MapChangedEventHandler2EventSource => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "MapChangedEventHandlerEventSource`2"u8); /// - /// Gets the for Windows.Foundation.TrustLevel. + /// Gets the for Windows.Foundation.TrustLevel. /// public TypeReference TrustLevel => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "TrustLevel"u8); /// - /// Gets the for Windows.Foundation.Point. + /// Gets the for Windows.Foundation.Point. /// public TypeReference Point => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "Point"u8); /// - /// Gets the for Windows.Foundation.Rect. + /// Gets the for Windows.Foundation.Rect. /// public TypeReference Rect => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "Rect"u8); /// - /// Gets the for Windows.Foundation.Size. + /// Gets the for Windows.Foundation.Size. /// public TypeReference Size => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "Size"u8); /// - /// Gets the for Windows.Foundation.AsyncStatus. + /// Gets the for Windows.Foundation.AsyncStatus. /// public TypeReference AsyncStatus => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "AsyncStatus"u8); /// - /// Gets the for Windows.Foundation.IAsyncInfo. + /// Gets the for Windows.Foundation.IAsyncInfo. /// public TypeReference IAsyncInfo => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "IAsyncInfo"u8); /// - /// Gets the for Windows.Foundation.IAsyncAction. + /// Gets the for Windows.Foundation.IAsyncAction. /// public TypeReference IAsyncAction => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "IAsyncAction"u8); /// - /// Gets the for Windows.Foundation.AsyncActionCompletedHandler. + /// Gets the for Windows.Foundation.AsyncActionCompletedHandler. /// public TypeReference AsyncActionCompletedHandler => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "AsyncActionCompletedHandler"u8); /// - /// Gets the for Windows.Foundation.IAsyncActionWithProgress<TProgress>. + /// Gets the for Windows.Foundation.IAsyncActionWithProgress<TProgress>. /// public TypeReference IAsyncActionWithProgress1 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "IAsyncActionWithProgress`1"u8); /// - /// Gets the for Windows.Foundation.AsyncActionProgressHandler<TProgress>. + /// Gets the for Windows.Foundation.AsyncActionProgressHandler<TProgress>. /// public TypeReference AsyncActionProgressHandler1 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "AsyncActionProgressHandler`1"u8); /// - /// Gets the for Windows.Foundation.AsyncActionWithProgressCompletedHandler<TProgress>. + /// Gets the for Windows.Foundation.AsyncActionWithProgressCompletedHandler<TProgress>. /// public TypeReference AsyncActionWithProgressCompletedHandler1 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "AsyncActionWithProgressCompletedHandler`1"u8); /// - /// Gets the for Windows.Foundation.IAsyncOperation<TResult>. + /// Gets the for Windows.Foundation.IAsyncOperation<TResult>. /// public TypeReference IAsyncOperation1 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "IAsyncOperation`1"u8); /// - /// Gets the for Windows.Foundation.AsyncOperationCompletedHandler<TResult>. + /// Gets the for Windows.Foundation.AsyncOperationCompletedHandler<TResult>. /// public TypeReference AsyncOperationCompletedHandler1 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "AsyncOperationCompletedHandler`1"u8); /// - /// Gets the for Windows.Foundation.IAsyncOperationWithProgress<TResult, TProgress>. + /// Gets the for Windows.Foundation.IAsyncOperationWithProgress<TResult, TProgress>. /// public TypeReference IAsyncOperationWithProgress2 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "IAsyncOperationWithProgress`2"u8); /// - /// Gets the for Windows.Foundation.AsyncOperationProgressHandler<TResult, TProgress>. + /// Gets the for Windows.Foundation.AsyncOperationProgressHandler<TResult, TProgress>. /// public TypeReference AsyncOperationProgressHandler2 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "AsyncOperationProgressHandler`2"u8); /// - /// Gets the for Windows.Foundation.AsyncOperationWithProgressCompletedHandler<TResult>. + /// Gets the for Windows.Foundation.AsyncOperationWithProgressCompletedHandler<TResult>. /// public TypeReference AsyncOperationWithProgressCompletedHandler2 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "AsyncOperationWithProgressCompletedHandler`2"u8); @@ -1049,24 +1054,24 @@ public InteropReferences( returnType: RuntimeTypeHandle.ToValueTypeSignature())); /// - /// Gets the for . + /// Gets the for . /// public MemberReference AttributeUsageAttribute_ctor_AttributeTargets => field ??= AttributeUsageAttribute.CreateConstructorReference( corLibTypeFactory: _corLibTypeFactory, parameterTypes: [AttributeTargets.ToValueTypeSignature()]); /// - /// Gets the for , using . + /// Gets the for , using . /// public MemberReference TypeMapAttributeWindowsRuntimeComWrappersTypeMapGroup_ctor_TrimTarget => field ??= TypeMapAttribute1_ctor_TrimTarget(WindowsRuntimeComWrappersTypeMapGroup.ToReferenceTypeSignature()); /// - /// Gets the for , using . + /// Gets the for , using . /// public MemberReference TypeMapAssociationAttributeWindowsRuntimeComWrappersTypeMapGroup_ctor => field ??= TypeMapAssociationAttribute1_ctor(WindowsRuntimeComWrappersTypeMapGroup.ToReferenceTypeSignature()); /// - /// Gets the for , using . + /// Gets the for , using . /// public MemberReference TypeMapAssociationAttributeDynamicInterfaceCastableImplementationTypeMapGroup_ctor => field ??= TypeMapAssociationAttribute1_ctor(DynamicInterfaceCastableImplementationTypeMapGroup.ToReferenceTypeSignature()); @@ -1184,27 +1189,27 @@ public InteropReferences( _corLibTypeFactory.Int32])); /// - /// Gets the for . + /// Gets the for . /// public MemberReference FixedAddressValueTypeAttribute_ctor => field ??= FixedAddressValueTypeAttribute.CreateConstructorReference(_corLibTypeFactory); /// - /// Gets the for . + /// Gets the for . /// public MemberReference DynamicInterfaceCastableImplementationAttribute_ctor => field ??= DynamicInterfaceCastableImplementationAttribute.CreateConstructorReference(_corLibTypeFactory); /// - /// Gets the for . + /// Gets the for . /// public MemberReference IsReadOnlyAttribute_ctor => field ??= IsReadOnlyAttribute.CreateConstructorReference(_corLibTypeFactory); /// - /// Gets the for . + /// Gets the for . /// public MemberReference ScopedRefAttribute_ctor => field ??= ScopedRefAttribute.CreateConstructorReference(_corLibTypeFactory); /// - /// Gets the for . + /// Gets the for . /// public MemberReference UnmanagedCallersOnlyAttribute_ctor => field ??= UnmanagedCallersOnlyAttribute.CreateConstructorReference(_corLibTypeFactory); @@ -1448,14 +1453,14 @@ public InteropReferences( parameterTypes: [WindowsRuntimeObjectReference.ToReferenceTypeSignature()])); /// - /// Gets the for 's get_NativeObjectReference method. + /// Gets the for 's get_NativeObjectReference method. /// public MemberReference WindowsRuntimeObjectget_NativeObjectReference => field ??= WindowsRuntimeObject .CreateMemberReference("get_NativeObjectReference"u8, MethodSignature.CreateInstance( returnType: WindowsRuntimeObjectReference.ToReferenceTypeSignature())); /// - /// Gets the for 's GetObjectReferenceForInterface method. + /// Gets the for 's GetObjectReferenceForInterface method. /// public MemberReference WindowsRuntimeObjectGetObjectReferenceForInterface => field ??= WindowsRuntimeObject .CreateMemberReference("GetObjectReferenceForInterface"u8, MethodSignature.CreateInstance( @@ -1463,7 +1468,7 @@ public InteropReferences( parameterTypes: [RuntimeTypeHandle.ToValueTypeSignature()])); /// - /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeInterface.get_IID(). + /// Gets the for WindowsRuntime.InteropServices.IWindowsRuntimeInterface.get_IID(). /// public MemberReference IWindowsRuntimeInterfaceget_IID => field ??= IWindowsRuntimeInterface .CreateMemberReference("get_IID"u8, MethodSignature.CreateStatic( @@ -1640,6 +1645,16 @@ public InteropReferences( returnType: AbiType.ToValueTypeSignature(), parameterTypes: [Type.ToReferenceTypeSignature()])); + /// + /// Gets the for ABI.System.TypeMarshaller.ConvertToUnmanagedUnsafe. + /// + public MemberReference TypeMarshallerConvertToUnmanagedUnsafe => field ??= TypeMarshaller + .CreateMemberReference("ConvertToUnmanagedUnsafe"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Void, + parameterTypes: [ + Type.ToReferenceTypeSignature(), + TypeReference.MakeByReferenceType()])); + /// /// Gets the for ABI.System.TypeMarshaller.Dispose. /// @@ -1752,6 +1767,20 @@ public InteropReferences( CreateComInterfaceFlags.ToValueTypeSignature(), Guid.ToValueTypeSignature().MakeByReferenceType()])); + /// + /// Gets the for WindowsRuntime.InteropServices.TypeReference.GetPinnableReference. + /// + public MemberReference TypeReferenceGetPinnableReference => field ??= TypeReference + .CreateMemberReference("GetPinnableReference"u8, MethodSignature.CreateInstance( + returnType: _corLibTypeFactory.Byte.MakeByReferenceType())); + + /// + /// Gets the for WindowsRuntime.InteropServices.TypeReference.ConvertToUnmanagedUnsafe. + /// + public MemberReference TypeReferenceConvertToUnmanagedUnsafe => field ??= TypeReference + .CreateMemberReference("ConvertToUnmanagedUnsafe"u8, MethodSignature.CreateInstance( + returnType: AbiType.ToValueTypeSignature())); + /// /// Gets the for WindowsRuntime.InteropServices.HStringMarshaller.ConvertToUnmanaged. /// @@ -1872,7 +1901,7 @@ public MemberReference ReadOnlySpan1_ctor(SzArrayTypeSignature arrayType) } /// - /// Gets the for . + /// Gets the for . /// /// The type map group to use. public MemberReference TypeMapAttribute1_ctor_TrimTarget(TypeSignature typeMapGroup) @@ -1889,7 +1918,7 @@ public MemberReference TypeMapAttribute1_ctor_TrimTarget(TypeSignature typeMapGr } /// - /// Gets the for . + /// Gets the for . /// /// The type map group to use. public MemberReference TypeMapAssociationAttribute1_ctor(TypeSignature typeMapGroup) From e67f2e5f6ec0f4c70883e4639fed29979c46a013 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 19:02:27 -0800 Subject: [PATCH 27/31] Handle Type parameters in interop method rewriting Introduces RewriteBodyForTypeOfType to properly handle parameters of type 'Type' in interop method rewriting. This includes declaring necessary local variables, pinning, marshalling, and cleanup logic for TypeReference parameters. --- ...ropMethodRewriteFactory.NativeParameter.cs | 52 +++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs index ba282fe77..d1c3dc141 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs @@ -164,9 +164,14 @@ public static void RewriteMethod( } else if (parameterType.IsTypeOfType(interopReferences)) { - // TODO - body.Instructions.ReferenceRemoveRange(tryMarker, finallyMarker); - body.Instructions.ReferenceReplaceRange(loadMarker, new CilInstruction(Ldnull)); + RewriteBodyForTypeOfType( + body: body, + tryMarker: tryMarker, + loadMarker: loadMarker, + finallyMarker: finallyMarker, + parameterIndex: parameterIndex, + interopReferences: interopReferences, + module: module); } else if (parameterType.IsTypeOfException(interopReferences)) { @@ -288,5 +293,46 @@ private static void RewriteBody( HandlerEnd = nop_finallyEnd.CreateLabel() }); } + + /// + /// The target body to perform two-pass code generation on. + private static void RewriteBodyForTypeOfType( + CilMethodBody body, + CilInstruction tryMarker, + CilInstruction loadMarker, + CilInstruction finallyMarker, + int parameterIndex, + InteropReferences interopReferences, + ModuleDefinition module) + { + // Declare the local variables: + // [0]: 'TypeReference' (for 'typeReference') + // [1]: 'ref byte' (for the pinned type reference) + CilLocalVariable loc_0_typeReference = new(interopReferences.TypeReference.Import(module).ToValueTypeSignature()); + CilLocalVariable loc_1_pinnedTypeReference = new(interopReferences.CorLibTypeFactory.Byte.MakeByReferenceType().MakePinnedType()); + + body.LocalVariables.Add(loc_0_typeReference); + body.LocalVariables.Add(loc_1_pinnedTypeReference); + + // Get the 'TypeReference' value and pin it + body.Instructions.ReferenceReplaceRange(tryMarker, [ + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Ldloca_S, loc_0_typeReference), + new CilInstruction(Call, interopReferences.TypeMarshallerConvertToUnmanagedUnsafe.Import(module)), + new CilInstruction(Ldloca_S, loc_0_typeReference), + new CilInstruction(Call, interopReferences.TypeReferenceGetPinnableReference.Import(module)), + CilInstruction.CreateStloc(loc_1_pinnedTypeReference, body)]); + + // Get the ABI 'Type' value and pass it as a parameter + body.Instructions.ReferenceReplaceRange(loadMarker, [ + new CilInstruction(Ldloca_S, loc_0_typeReference), + new CilInstruction(Call, interopReferences.TypeReferenceConvertToUnmanagedUnsafe.Import(module))]); + + // Unpin the local (just assign 'null' to it) + body.Instructions.ReferenceReplaceRange(finallyMarker, [ + new CilInstruction(Ldc_I4_0), + new CilInstruction(Conv_U), + CilInstruction.CreateStloc(loc_1_pinnedTypeReference, body)]); + } } } \ No newline at end of file From 84378f60e7d01e81684452579c1066c52ab1df2e Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 20:49:51 -0800 Subject: [PATCH 28/31] Add references for Nullable and HString marshalling Introduces new type and member references for Nullable, HStringReference, and related marshalling methods. Also adds references for string member accessors and updates XML documentation for clarity. --- .../References/InteropReferences.cs | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/src/WinRT.Interop.Generator/References/InteropReferences.cs b/src/WinRT.Interop.Generator/References/InteropReferences.cs index 86c27fea9..797a43b9c 100644 --- a/src/WinRT.Interop.Generator/References/InteropReferences.cs +++ b/src/WinRT.Interop.Generator/References/InteropReferences.cs @@ -138,6 +138,11 @@ public InteropReferences( /// public TypeReference Nullable1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "Nullable`1"u8); + /// + /// Gets the for of . + /// + public GenericInstanceTypeSignature NullableInt32 => field ??= Nullable1.MakeGenericValueType(_corLibTypeFactory.Int32); + /// /// Gets the for . /// @@ -174,22 +179,22 @@ public InteropReferences( public TypeReference ReadOnlySpan1 => field ??= _corLibTypeFactory.CorLibScope.CreateTypeReference("System"u8, "ReadOnlySpan`1"u8); /// - /// Gets the for of . + /// Gets the for of . /// public GenericInstanceTypeSignature ReadOnlySpanByte => field ??= ReadOnlySpan1.MakeGenericValueType(_corLibTypeFactory.Byte); /// - /// Gets the for of . + /// Gets the for of . /// public GenericInstanceTypeSignature ReadOnlySpanChar => field ??= ReadOnlySpan1.MakeGenericValueType(_corLibTypeFactory.Char); /// - /// Gets the for of . + /// Gets the for of . /// public GenericInstanceTypeSignature ReadOnlySpanUInt16 => field ??= ReadOnlySpan1.MakeGenericValueType(_corLibTypeFactory.UInt16); /// - /// Gets the for of . + /// Gets the for of . /// public GenericInstanceTypeSignature ReadOnlySpanInt32 => field ??= ReadOnlySpan1.MakeGenericValueType(_corLibTypeFactory.Int32); @@ -853,6 +858,11 @@ public InteropReferences( /// public TypeReference TypeReference => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "TypeReference"u8); + /// + /// Gets the for WindowsRuntime.InteropServices.Marshalling.HStringReference. + /// + public TypeReference HStringReference => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices.Marshalling"u8, "HStringReference"u8); + /// /// Gets the for WindowsRuntime.InteropServices.HStringMarshaller. /// @@ -1023,6 +1033,21 @@ public InteropReferences( /// public TypeReference AsyncOperationWithProgressCompletedHandler2 => field ??= _windowsRuntimeModule.CreateTypeReference("Windows.Foundation"u8, "AsyncOperationWithProgressCompletedHandler`2"u8); + /// + /// Gets the for . + /// + public MemberReference Stringget_Length => field ??= _corLibTypeFactory.String + .ToTypeDefOrRef() + .CreateMemberReference("get_Length"u8, MethodSignature.CreateInstance(_corLibTypeFactory.Int32)); + + /// + /// Gets the for . + /// + public MemberReference StringGetPinnableReference => field ??= _corLibTypeFactory.String + .ToTypeDefOrRef() + .CreateMemberReference("GetPinnableReference"u8, MethodSignature.CreateInstance( + returnType: _corLibTypeFactory.Char.MakeByReferenceType().MakeModifierType(InAttribute, isRequired: true))); + /// /// Gets the for . /// @@ -1781,6 +1806,13 @@ public InteropReferences( .CreateMemberReference("ConvertToUnmanagedUnsafe"u8, MethodSignature.CreateInstance( returnType: AbiType.ToValueTypeSignature())); + /// + /// Gets the for WindowsRuntime.InteropServices.HStringReference.get_HString. + /// + public MemberReference HStringReferenceget_HString => field ??= HStringReference + .CreateMemberReference("get_HString"u8, MethodSignature.CreateInstance( + returnType: _corLibTypeFactory.Void.MakePointerType())); + /// /// Gets the for WindowsRuntime.InteropServices.HStringMarshaller.ConvertToUnmanaged. /// @@ -1789,6 +1821,17 @@ public InteropReferences( returnType: _corLibTypeFactory.Void.MakePointerType(), parameterTypes: [ReadOnlySpanChar])); + /// + /// Gets the for WindowsRuntime.InteropServices.HStringMarshaller.ConvertToUnmanagedUnsafe. + /// + public MemberReference HStringMarshallerConvertToUnmanagedUnsafe => field ??= HStringMarshaller + .CreateMemberReference("ConvertToUnmanagedUnsafe"u8, MethodSignature.CreateStatic( + returnType: _corLibTypeFactory.Void, + parameterTypes: [ + _corLibTypeFactory.Char.MakePointerType(), + Nullable1.MakeGenericValueType(_corLibTypeFactory.Int32), + HStringReference.ToValueTypeSignature().MakeByReferenceType()])); + /// /// Gets the for WindowsRuntime.InteropServices.HStringMarshaller.ConvertToManaged. /// @@ -1889,6 +1932,22 @@ public MemberReference EventRegistrationTokenTableRemoveEventHandler(TypeSignatu new GenericParameterSignature(GenericParameterType.Type, 0).MakeByReferenceType()])); } + /// + /// Gets the for the .ctor method of a given nullable value type. + /// + /// The input value type. + public MemberReference Nullable1_ctor(TypeSignature valueType) + { + // Get the special delegate constructor taking the target and function pointer. We leverage this to create + // a delegate instance that directly wraps our 'WindowsRuntimeObjectReference' object and 'Invoke' method. + return Nullable1 + .MakeGenericValueType(valueType) + .ToTypeDefOrRef() + .CreateConstructorReference( + corLibTypeFactory: _corLibTypeFactory, + parameterTypes: [new GenericParameterSignature(GenericParameterType.Type, 0)]); + } + /// /// Gets the for 's constructor (of an SZ array type). /// From 6f40afaa1555c8247125000355bee0bba4ba4048 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 20:50:21 -0800 Subject: [PATCH 29/31] Handle string parameters in interop method rewriting Implemented RewriteBodyForTypeOfString to correctly process string parameters by pinning, length calculation, and HStringReference marshalling. This replaces the previous placeholder logic and ensures proper handling of string arguments in interop scenarios. --- ...ropMethodRewriteFactory.NativeParameter.cs | 82 ++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs index d1c3dc141..71acbfd64 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs @@ -158,9 +158,14 @@ public static void RewriteMethod( } else if (parameterType.IsTypeOfString()) { - // TODO - body.Instructions.ReferenceRemoveRange(tryMarker, finallyMarker); - body.Instructions.ReferenceReplaceRange(loadMarker, new CilInstruction(Ldnull)); + RewriteBodyForTypeOfString( + body: body, + tryMarker: tryMarker, + loadMarker: loadMarker, + finallyMarker: finallyMarker, + parameterIndex: parameterIndex, + interopReferences: interopReferences, + module: module); } else if (parameterType.IsTypeOfType(interopReferences)) { @@ -294,6 +299,77 @@ private static void RewriteBody( }); } + /// + /// The target body to perform two-pass code generation on. + private static void RewriteBodyForTypeOfString( + CilMethodBody body, + CilInstruction tryMarker, + CilInstruction loadMarker, + CilInstruction finallyMarker, + int parameterIndex, + InteropReferences interopReferences, + ModuleDefinition module) + { + // Declare the local variables: + // [0]: 'ref char' (for the pinned 'string') + // [1]: 'HStringReference' (for 'hstringReference') + // [2]: 'int?' (for 'length') + CilLocalVariable loc_0_pinnedString = new(interopReferences.CorLibTypeFactory.Char.MakeByReferenceType().MakePinnedType()); + CilLocalVariable loc_1_hstringReference = new(interopReferences.HStringReference.Import(module).ToValueTypeSignature()); + CilLocalVariable loc_2_length = new(interopReferences.Nullable1.MakeGenericValueType(interopReferences.CorLibTypeFactory.Int32).Import(module)); + + body.LocalVariables.Add(loc_0_pinnedString); + body.LocalVariables.Add(loc_1_hstringReference); + body.LocalVariables.Add(loc_2_length); + + // Prepare the jump labels + CilInstruction ldarg_pinning = CilInstruction.CreateLdarg(parameterIndex); + CilInstruction ldarg_lengthNullCheck = CilInstruction.CreateLdarg(parameterIndex); + CilInstruction ldarg_getLength = CilInstruction.CreateLdarg(parameterIndex); + CilInstruction ldloca_s_getHStringReference = new(Ldloca_S, loc_1_hstringReference); + + // Pin the input 'string' value, get the (possibly 'null') length, and create the 'HStringReference' value + body.Instructions.ReferenceReplaceRange(tryMarker, [ + + // fixed (char* p = value) { } + CilInstruction.CreateLdarg(parameterIndex), + new CilInstruction(Brtrue_S, ldarg_pinning.CreateLabel()), + new CilInstruction(Ldc_I4_0), + new CilInstruction(Conv_U), + new CilInstruction(Br_S, ldarg_lengthNullCheck.CreateLabel()), + ldarg_pinning, + new CilInstruction(Call, interopReferences.StringGetPinnableReference.Import(module)), + CilInstruction.CreateStloc(loc_0_pinnedString, body), + CilInstruction.CreateLdloc(loc_0_pinnedString, body), + new CilInstruction(Conv_U), + + // int? length = value?.Length; + ldarg_lengthNullCheck, + new CilInstruction(Brtrue_S, ldarg_getLength.CreateLabel()), + new CilInstruction(Ldloca_S, loc_2_length), + new CilInstruction(Initobj, interopReferences.NullableInt32.Import(module).ToTypeDefOrRef()), + CilInstruction.CreateLdloc(loc_2_length, body), + new CilInstruction(Br_S, ldloca_s_getHStringReference.CreateLabel()), + ldarg_getLength, + new CilInstruction(Call, interopReferences.Stringget_Length.Import(module)), + new CilInstruction(Newobj, interopReferences.Nullable1_ctor(interopReferences.CorLibTypeFactory.Int32).Import(module)), + + // HStringMarshaller.ConvertToUnmanagedUnsafe(p, length, out HStringReference hstringReference); + ldloca_s_getHStringReference, + new CilInstruction(Call, interopReferences.HStringMarshallerConvertToUnmanagedUnsafe.Import(module))]); + + // Get the 'HString' value from the reference and pass it as a parameter + body.Instructions.ReferenceReplaceRange(loadMarker, [ + new CilInstruction(Ldloca_S, loc_1_hstringReference), + new CilInstruction(Call, interopReferences.HStringReferenceget_HString.Import(module))]); + + // Unpin the local (just assign 'null' to it) + body.Instructions.ReferenceReplaceRange(finallyMarker, [ + new CilInstruction(Ldc_I4_0), + new CilInstruction(Conv_U), + CilInstruction.CreateStloc(loc_0_pinnedString, body)]); + } + /// /// The target body to perform two-pass code generation on. private static void RewriteBodyForTypeOfType( From d65e01ca7bf5047d023619ce13242c93c0e67fe3 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 20:57:26 -0800 Subject: [PATCH 30/31] Fix incorrect value type for dictionaries Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Builders/InteropTypeDefinitionBuilder.IDictionary2.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs index a289fa335..b62708d51 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs @@ -90,7 +90,7 @@ public static void Vftbl( TypeSignature valueType = dictionaryType.TypeArguments[1]; bool isKeyReferenceType = keyType.HasReferenceAbiType(interopReferences); - bool isValueReferenceType = keyType.HasReferenceAbiType(interopReferences); + bool isValueReferenceType = valueType.HasReferenceAbiType(interopReferences); // We can share the vtable type for 'void*' when both key and value types are reference types if (isKeyReferenceType && isValueReferenceType) From a3af8870519a3fab36dc585e4dc7c189d533cde7 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 20:59:01 -0800 Subject: [PATCH 31/31] Update XML docs for ABI type methods Clarified and corrected XML documentation for HasReferenceAbiType and GetAbiType methods to better describe their return values and behavior. --- .../Extensions/WindowsRuntimeExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs index 7564c5550..1ade639d2 100644 --- a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs @@ -487,10 +487,10 @@ public bool IsTrackerSupportRequired(InteropReferences interopReferences) } /// - /// Gets the ABI type for a given type. + /// Gets whether a given type has an ABI type that is a reference type. /// /// The instance to use. - /// The ABi type for the input type. + /// Whether the input type has an ABI type that is a reference type. public bool HasReferenceAbiType(InteropReferences interopReferences) { // All constructed generics will use 'void*' for the ABI type @@ -525,7 +525,7 @@ public bool HasReferenceAbiType(InteropReferences interopReferences) /// Gets the ABI type for a given type. /// /// The instance to use. - /// The ABi type for the input type. + /// The ABI type for the input type. public TypeSignature GetAbiType(InteropReferences interopReferences) { // All constructed generics will use 'void*' for the ABI type. This applies to both reference