Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
4b680f1
Add HStringArrayMarshaller for HSTRING array marshalling
Sergio0694 Jan 6, 2026
c2ae729
Add marshaller for blittable value type arrays
Sergio0694 Jan 9, 2026
2171094
Refactor and rename blittable array marshaller class
Sergio0694 Jan 10, 2026
4d6f194
Rename and update WindowsRuntimeBlittableValueTypeArrayMarshaller
Sergio0694 Jan 10, 2026
fd41cf7
Fix typo in comment in EventSource<T>.cs
Sergio0694 Jan 10, 2026
e2ea531
Add marshaller for unmanaged WinRT value type arrays
Sergio0694 Jan 10, 2026
c69cc48
Add managed value type array marshaller for WinRT
Sergio0694 Jan 11, 2026
0488b42
Add marshallers for Windows Runtime reference type arrays
Sergio0694 Jan 11, 2026
d7fedc9
Fix loop variable type and index in array marshaller
Sergio0694 Jan 11, 2026
2058d8f
Add marshallers for Windows Runtime KeyValuePair arrays
Sergio0694 Jan 11, 2026
170fec4
Move and update HStringArrayMarshaller for SzArrays
Sergio0694 Jan 11, 2026
0402292
Add TypeArrayMarshaller for WinRT Type arrays
Sergio0694 Jan 11, 2026
88a41c7
Add ExceptionArrayMarshaller for WinRT exception arrays
Sergio0694 Jan 11, 2026
79ed703
Remove unnecessary MethodImpl attributes from marshallers
Sergio0694 Jan 11, 2026
71b2b7c
Move Free method to generic marshaller class
Sergio0694 Jan 11, 2026
d9ce60d
Refactor array helper usage in marshallers
Sergio0694 Jan 11, 2026
049ff0c
Add array marshaller references and methods
Sergio0694 Jan 12, 2026
a088218
Remove generic parameter from Free method
Sergio0694 Jan 13, 2026
e046b7a
Remove WindowsRuntimeArrayHelpers references and marshalling stubs
Sergio0694 Jan 13, 2026
e824ee7
Refactor class comments to use <inheritdoc/>
Sergio0694 Jan 13, 2026
dbd2eb0
Add SzArrayElementMarshaller for array element marshalling
Sergio0694 Jan 13, 2026
db83d26
Refactor ConvertToManaged methods to use Nop and Ret
Sergio0694 Jan 13, 2026
644351e
Add support for ConvertToUnmanaged method rewrites
Sergio0694 Jan 13, 2026
8ab1912
Refactor ConvertToUnmanaged method generation
Sergio0694 Jan 13, 2026
b42004e
Refactor ConvertToUnmanaged rewrite to RawRetVal
Sergio0694 Jan 13, 2026
b6d86df
Add support for Dispose method rewrite in interop generator
Sergio0694 Jan 13, 2026
ed8f817
Remove marker reference for blittable parameters
Sergio0694 Jan 13, 2026
4d1ace3
Refactor disposal logic in SzArrayElementMarshaller
Sergio0694 Jan 13, 2026
93697d1
Add Free method to KeyValuePair array marshaller
Sergio0694 Jan 14, 2026
3dd06c1
Add SzArrayMarshaller factory and update docs
Sergio0694 Jan 14, 2026
e75ef8a
Add marshaller methods for string, Type, and Exception arrays
Sergio0694 Jan 14, 2026
f910f46
Refactor SZ array marshaller to use emit state
Sergio0694 Jan 14, 2026
f60773e
Remove SzArrayMarshaller helper class
Sergio0694 Jan 14, 2026
04cf3e5
Refactor key-value pair array marshaller argument handling
Sergio0694 Jan 14, 2026
ac007e3
Add GetRawAbiType method to WindowsRuntimeExtensions
Sergio0694 Jan 14, 2026
27969c2
Refactor element marshaller creation logic
Sergio0694 Jan 14, 2026
8e1865c
Refactor type name generation for arrays and generics
Sergio0694 Jan 14, 2026
afffd88
Refactor array marshaller Free logic to shared class
Sergio0694 Jan 14, 2026
6d5efd4
Refactor array marshaller free method references
Sergio0694 Jan 14, 2026
abf1bab
Add isValueType parameter to element marshaller creation
Sergio0694 Jan 14, 2026
6a2978d
Use ReferenceType for SzArrayMarshaller
Sergio0694 Jan 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using AsmResolver.PE.DotNet.Cil;
using AsmResolver.PE.DotNet.Metadata.Tables;
using WindowsRuntime.InteropGenerator.Factories;
using WindowsRuntime.InteropGenerator.Generation;
using WindowsRuntime.InteropGenerator.References;
using static AsmResolver.PE.DotNet.Cil.CilOpCodes;

Expand All @@ -26,121 +27,129 @@ public static class SzArray
/// </summary>
/// <param name="arrayType">The <see cref="SzArrayTypeSignature"/> for the SZ array type.</param>
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <param name="emitState">The emit state for this invocation.</param>
/// <param name="module">The module that will contain the type being created.</param>
/// <param name="marshallerType">The resulting marshaller type.</param>
public static void Marshaller(
SzArrayTypeSignature arrayType,
InteropReferences interopReferences,
InteropGeneratorEmitState emitState,
ModuleDefinition module,
out TypeDefinition marshallerType)
{
TypeSignature elementType = arrayType.BaseType;
TypeSignature elementAbiType = elementType.GetAbiType(interopReferences);

// We're declaring an 'internal static class' type
marshallerType = new(
ns: InteropUtf8NameFactory.TypeNamespace(arrayType),
name: InteropUtf8NameFactory.TypeName(arrayType, "Marshaller"),
attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit,
baseType: module.CorLibTypeFactory.Object.ToTypeDefOrRef());

module.TopLevelTypes.Add(marshallerType);

// Define the 'ConvertToUnmanaged' method as follows:
//
// public static void ConvertToUnmanaged(ReadOnlySpan<<ELEMENT_TYPE>>, out uint size, out <ABI_ELEMENT_TYPE>* array)
MethodDefinition convertToUnmanagedMethod = new(
name: "ConvertToUnmanaged"u8,
attributes: MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
signature: MethodSignature.CreateStatic(
returnType: module.CorLibTypeFactory.Void,
parameterTypes: [
interopReferences.ReadOnlySpan1.MakeGenericValueType(elementType).Import(module),
module.CorLibTypeFactory.UInt32.MakeByReferenceType(),
elementAbiType.Import(module).MakePointerType().MakeByReferenceType()]))
// Emit the right marshaller based on the element type. We special case all different
// kinds of element types because some need specialized marshallers, and some need
// a generated element marshaller type. The marshaller itself just forwards all calls.
if (elementType.IsBlittable(interopReferences))
{
CilOutParameterIndices = [2, 3],
CilInstructions =
{
{ Ldnull },
{ Throw } // TODO
}
};

marshallerType.Methods.Add(convertToUnmanagedMethod);

// Define the 'ConvertToManaged' method as follows:
//
// public static <ELEMENT_TYPE>[] ConvertToManaged(uint size, <ABI_ELEMENT_TYPE>* value)
MethodDefinition convertToManagedMethod = new(
name: "ConvertToManaged"u8,
attributes: MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
signature: MethodSignature.CreateStatic(
returnType: arrayType.Import(module),
parameterTypes: [
module.CorLibTypeFactory.UInt32,
elementAbiType.Import(module).MakePointerType()]))
marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.BlittableValueType(
arrayType: arrayType,
interopReferences: interopReferences,
module: module);

module.TopLevelTypes.Add(marshallerType);
}
else if (elementType.IsConstructedKeyValuePairType(interopReferences))
{
CilInstructions =
{
{ Ldnull },
{ Throw } // TODO
}
};

marshallerType.Methods.Add(convertToManagedMethod);

// Define the 'CopyToManaged' method as follows:
//
// public static void CopyToManaged(uint size, <ABI_ELEMENT_TYPE>* value, Span<<ELEMENT_TYPE>> destination)
MethodDefinition copyToManagedMethod = new(
name: "CopyToManaged"u8,
attributes: MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
signature: MethodSignature.CreateStatic(
returnType: module.CorLibTypeFactory.Void,
parameterTypes: [
module.CorLibTypeFactory.UInt32,
elementAbiType.Import(module).MakePointerType(),
interopReferences.Span1.MakeGenericValueType(elementType).Import(module)]))
TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.KeyValuePair(
arrayType: arrayType,
interopReferences: interopReferences,
emitState: emitState,
module: module);

module.TopLevelTypes.Add(elementMarshallerType);

marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.KeyValuePair(
arrayType: arrayType,
elementMarshallerType: elementMarshallerType,
interopReferences: interopReferences,
module: module);

module.TopLevelTypes.Add(marshallerType);
}
else if (elementType.IsManagedValueType(interopReferences))
{
CilInstructions =
{
{ Ldnull },
{ Throw } // TODO
}
};

marshallerType.Methods.Add(copyToManagedMethod);

// Define the 'CopyToUnmanaged' method as follows:
//
// public static void CopyToUnmanaged(ReadOnlySpan<<ELEMENT_TYPE>> value, uint size, <ABI_ELEMENT_TYPE>* destination)
MethodDefinition copyToUnmanagedMethod = new(
name: "CopyToUnmanaged"u8,
attributes: MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
signature: MethodSignature.CreateStatic(
returnType: module.CorLibTypeFactory.Void,
parameterTypes: [
interopReferences.ReadOnlySpan1.MakeGenericValueType(elementType).Import(module),
module.CorLibTypeFactory.UInt32,
elementAbiType.Import(module).MakePointerType()]))
TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.ManagedValueType(
arrayType: arrayType,
interopReferences: interopReferences,
emitState: emitState,
module: module);

module.TopLevelTypes.Add(elementMarshallerType);

marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.ManagedValueType(
arrayType: arrayType,
elementMarshallerType: elementMarshallerType,
interopReferences: interopReferences,
module: module);

module.TopLevelTypes.Add(marshallerType);
}
else if (elementType.IsValueType)
{
CilInstructions =
{
{ Ldnull },
{ Throw } // TODO
}
};

marshallerType.Methods.Add(copyToUnmanagedMethod);

// Define the 'Free' method
MethodDefinition freeMethod = InteropMethodDefinitionFactory.SzArrayMarshaller.Free(
arrayType,
interopReferences,
module);

marshallerType.Methods.Add(freeMethod);
TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.UnmanagedValueType(
arrayType: arrayType,
interopReferences: interopReferences,
emitState: emitState,
module: module);

module.TopLevelTypes.Add(elementMarshallerType);

marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.UnmanagedValueType(
arrayType: arrayType,
elementMarshallerType: elementMarshallerType,
interopReferences: interopReferences,
module: module);

module.TopLevelTypes.Add(marshallerType);
}
else if (elementType.IsTypeOfString())
{
marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.String(
arrayType: arrayType,
interopReferences: interopReferences,
module: module);

module.TopLevelTypes.Add(marshallerType);
}
else if (elementType.IsTypeOfType(interopReferences))
{
marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.Type(
arrayType: arrayType,
interopReferences: interopReferences,
module: module);

module.TopLevelTypes.Add(marshallerType);
}
else if (elementType.IsTypeOfException(interopReferences))
{
marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.Exception(
arrayType: arrayType,
interopReferences: interopReferences,
module: module);

module.TopLevelTypes.Add(marshallerType);
}
else
{
TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.ReferenceType(
arrayType: arrayType,
interopReferences: interopReferences,
emitState: emitState,
module: module);

module.TopLevelTypes.Add(elementMarshallerType);

marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.ReferenceType(
arrayType: arrayType,
elementMarshallerType: elementMarshallerType,
interopReferences: interopReferences,
module: module);

module.TopLevelTypes.Add(marshallerType);
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,14 @@ public static WellKnownInteropException MethodRewriteSourceParameterTypeMismatch
return Exception(69, $"Parameter variable of type '{parameterType}' cannot be used to marshal a value of type '{returnType}' in generated interop method '{method}'.");
}

/// <summary>
/// A type doesn't have the <c>Dispose</c> method available.
/// </summary>
public static WellKnownInteropException MethodRewriteDisposeNotAvailableError(TypeSignature parameterType, MethodDefinition method)
{
return Exception(70, $"Value of type '{parameterType}' in generated interop method '{method}' cannot be disposed, as it is an unmanaged (or blittable) value type.");
}

/// <summary>
/// Creates a new exception with the specified id and message.
/// </summary>
Expand Down
16 changes: 16 additions & 0 deletions src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,22 @@ public TypeSignature GetAbiType(InteropReferences interopReferences)
// For all other cases (e.g. interfaces, classes, delegates, etc.), the ABI type is always a pointer
return interopReferences.CorLibTypeFactory.Void.MakePointerType();
}

/// <summary>
/// Gets the raw ABI type for a given type (without unwrapping).
/// </summary>
/// <param name="interopReferences">The <see cref="InteropReferences"/> instance to use.</param>
/// <returns>The raw ABI type for the input type.</returns>
public TypeSignature GetRawAbiType(InteropReferences interopReferences)
{
TypeSignature abiType = type.GetAbiType(interopReferences);

// If the ABI type is 'void*', the marshaller types return it as 'WindowsRuntimeObjectReferenceValue'.
// This allows callers to do proper lifetime management. For all other cases, the ABI type is the same.
return abiType.IsTypeOfVoidPointer()
? interopReferences.WindowsRuntimeObjectReferenceValue.ToValueTypeSignature()
: abiType;
}
}

extension(TypeDefinition type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@

namespace WindowsRuntime.InteropGenerator.Factories;

/// <summary>
/// A factory for interop method definitions.
/// </summary>
internal static partial class InteropMethodDefinitionFactory
/// <inheritdoc cref="InteropMethodDefinitionFactory"/>
internal partial class InteropMethodDefinitionFactory
{
/// <summary>
/// Helpers for impl types for <see cref="System.Collections.Generic.IEnumerator{T}"/> interfaces.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@

namespace WindowsRuntime.InteropGenerator.Factories;

/// <summary>
/// A factory for interop method definitions.
/// </summary>
internal static partial class InteropMethodDefinitionFactory
/// <inheritdoc cref="InteropMethodDefinitionFactory"/>
internal partial class InteropMethodDefinitionFactory
{
/// <summary>
/// Helpers for impl types for <see cref="System.Collections.Generic.IList{T}"/> interfaces.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@

namespace WindowsRuntime.InteropGenerator.Factories;

/// <summary>
/// A factory for interop method definitions.
/// </summary>
internal static partial class InteropMethodDefinitionFactory
/// <inheritdoc cref="InteropMethodDefinitionFactory"/>
internal partial class InteropMethodDefinitionFactory
{
/// <summary>
/// Helpers for impl types for <see cref="System.Collections.Generic.IReadOnlyDictionary{TKey, TValue}"/> interfaces.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@

namespace WindowsRuntime.InteropGenerator.Factories;

/// <summary>
/// A factory for interop method definitions.
/// </summary>
internal static partial class InteropMethodDefinitionFactory
/// <inheritdoc cref="InteropMethodDefinitionFactory"/>
internal partial class InteropMethodDefinitionFactory
{
/// <summary>
/// Helpers for impl types for <see cref="System.Collections.Generic.IReadOnlyList{T}"/> interfaces.
Expand Down
Loading
Loading