From 6128fd8804faba04c4c13888c296fe94af643602 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 14:44:50 -0800 Subject: [PATCH 01/32] 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 b1a205f6fb40bec9665d8a05e22d7c14d0aa5bc3 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 15:03:49 -0800 Subject: [PATCH 02/32] 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 f646f953c81ee03799ca0f98dd19ae1d411fea4b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 15:19:51 -0800 Subject: [PATCH 03/32] 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 8cd7a16ca3887faa44a653c70561d728a096e8f3 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 15:34:53 -0800 Subject: [PATCH 04/32] 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 34d21e3802245406ac0fd3a5bacfcc3335fcefad Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 15:59:40 -0800 Subject: [PATCH 05/32] 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 062602d23..f6c454734 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs @@ -54,8 +54,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 b03e88a0064283ade0b43308dbff037f3415bf2d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 19:03:32 -0800 Subject: [PATCH 06/32] 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 8d68617c6ae4e7019ae7b54c1dc3bc55f0e2db82 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:13:55 -0800 Subject: [PATCH 07/32] 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 291aed7e76024f6c656b28da4e15f0baa0055c7e Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:14:01 -0800 Subject: [PATCH 08/32] 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 7fc9a94eb003b7497f8095aad3d5fec44af17960 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:21:09 -0800 Subject: [PATCH 09/32] 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 4f39553717706ab5a49ec266b1a0f7c634c78024 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:22:58 -0800 Subject: [PATCH 10/32] 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 e0624120527ab8a67f296450cfa416b0f82daa62 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:25:10 -0800 Subject: [PATCH 11/32] 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 f5132117bf38456fc9faf7a4e65c2f6e31796234 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:27:31 -0800 Subject: [PATCH 12/32] 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 dfc88a9c2e2a77627a4f1840b89b93c6a8f2d9ca Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:48:04 -0800 Subject: [PATCH 13/32] 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 0f1762ababefc5562c0b1b0336dbdd2835872bcc Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:49:57 -0800 Subject: [PATCH 14/32] 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 5f04a0f21d23770571a3473b856b4a8b2da4bccc Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Dec 2025 20:52:27 -0800 Subject: [PATCH 15/32] 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 f6c454734..0410700ec 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs @@ -49,7 +49,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 8f688bbd3..3ef969097 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 f515f473f193f9852a218025200790260d81c36a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 11:46:05 -0800 Subject: [PATCH 16/32] 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 858c805acbaf14a27e7fb19a3efa08425c61a48d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 11:54:40 -0800 Subject: [PATCH 17/32] 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 0410700ec..e3b1bc8cb 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs @@ -73,12 +73,12 @@ public static void RewriteMethod( // If the return type is blittable, we can just load 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"))]); } @@ -97,7 +97,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))]); } @@ -115,7 +115,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))]); } @@ -123,7 +123,7 @@ 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))]); } @@ -137,7 +137,7 @@ public static void RewriteMethod( 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"))]); } @@ -154,7 +154,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 3ef969097..323fd85c9 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])); // 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 ab81c4b9f67a63bd6a75fad066e6e13081961501 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 12:13:13 -0800 Subject: [PATCH 18/32] 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 3d785b5ada4285c887a2c6ca316b4affe4e86699 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 12:22:09 -0800 Subject: [PATCH 19/32] 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 2db1e12a08517a6f9cf9f6310b89774943337a32 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 12:38:17 -0800 Subject: [PATCH 20/32] 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 bbcd2df61ae7470445d5fec432744c6f0a60dc52 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 12:39:59 -0800 Subject: [PATCH 21/32] 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 05c43bddf80d1e213754a8d67d5ec1bc352e5024 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 15:18:35 -0800 Subject: [PATCH 22/32] 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 9d58b6e28575405f16a8b5d7aeb5a9764990ac00 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 15:18:42 -0800 Subject: [PATCH 23/32] 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 368395cacc489716b4c2e2617ab479a17a70e6bc Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 15:24:54 -0800 Subject: [PATCH 24/32] 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 90aff58e8ceb43743d6991334afa65ec0ac2e83b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 15:26:50 -0800 Subject: [PATCH 25/32] 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 1e398322c8f23f7d42e0b556eabeded07dadbefe Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 19:02:20 -0800 Subject: [PATCH 26/32] 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 | 415 ++++++++++-------- 1 file changed, 222 insertions(+), 193 deletions(-) diff --git a/src/WinRT.Interop.Generator/References/InteropReferences.cs b/src/WinRT.Interop.Generator/References/InteropReferences.cs index a09d59b45..b1df59f58 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); @@ -204,822 +204,827 @@ public InteropReferences( 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); @@ -1054,24 +1059,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()); @@ -1189,27 +1194,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); @@ -1453,14 +1458,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( @@ -1468,7 +1473,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( @@ -1645,6 +1650,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. /// @@ -1757,6 +1772,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. /// @@ -1877,7 +1906,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) @@ -1894,7 +1923,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 fca3f01ccffd0b92b80ba479325b9c70df890ac5 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 19:02:27 -0800 Subject: [PATCH 27/32] 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 354f8acacb716b734f37f336c32ea47cd867cfe3 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 20:49:51 -0800 Subject: [PATCH 28/32] 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 b1df59f58..58836c1ac 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); @@ -858,6 +863,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. /// @@ -1028,6 +1038,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 . /// @@ -1786,6 +1811,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. /// @@ -1794,6 +1826,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. /// @@ -1894,6 +1937,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 7299097f470b9b686ce0d336fb12bef5de56cd1d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 20:50:21 -0800 Subject: [PATCH 29/32] 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 5715fdd7103162bf67c0eade97d8d06883ef2f00 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 20:57:26 -0800 Subject: [PATCH 30/32] 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 138ef25fdb62027e34d99964e21a7f8011f672ee Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Dec 2025 20:59:01 -0800 Subject: [PATCH 31/32] 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 From da42a7bdbff43203ab0e2ea7b85a92d0064079d5 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 15 Jan 2026 19:34:39 -0800 Subject: [PATCH 32/32] Update marshalling and pragma warning handling Replaces ReplaceRange with ReferenceReplaceRange for Type marshalling in ManagedParameter and adds CS8620 to pragma warnings in NativeParameter to address a Roslyn bug. --- .../Factories/InteropMethodRewriteFactory.ManagedParameter.cs | 2 +- .../Factories/InteropMethodRewriteFactory.NativeParameter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs index e3b1bc8cb..abf7da7e3 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.ManagedParameter.cs @@ -130,7 +130,7 @@ public static void RewriteMethod( else if (parameterType.IsTypeOfType(interopReferences)) { // When marshalling 'Type' values, we must use 'TypeMarshaller' (the ABI type is a value type) - body.Instructions.ReplaceRange(marker, [ + body.Instructions.ReferenceReplaceRange(marker, [ CilInstruction.CreateLdarg(parameterIndex), new CilInstruction(Call, interopReferences.TypeMarshallerConvertToManaged.Import(module))]); } diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs index 71acbfd64..799de0490 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodRewriteFactory.NativeParameter.cs @@ -12,7 +12,7 @@ using WindowsRuntime.InteropGenerator.References; using static AsmResolver.PE.DotNet.Cil.CilOpCodes; -#pragma warning disable CS1573 +#pragma warning disable CS1573, CS8620 // TODO: remove once Roslyn bug is fixed namespace WindowsRuntime.InteropGenerator.Factories;