PinnedMarshal has the "FromManaged" call in stateful marshallers, so that needs to happen before marshal in unmanaged to managed stubs.
tryStatements.Add(statements.InvokeStatement);
tryStatements.AddRange(statements.NotifyForSuccessfulInvoke);
- tryStatements.AddRange(statements.PinnedMarshal);
tryStatements.AddRange(statements.Marshal);
+ tryStatements.AddRange(statements.PinnedMarshal);
List<StatementSyntax> allStatements = setupStatements;
List<StatementSyntax> finallyStatements = new();
}
[Fact]
+ public void StatefulMarshalling()
+ {
+ var obj = CreateWrapper<StatefulMarshalling, IStatefulMarshalling>();
+ var data = new StatefulType() { i = 42 };
+
+ obj.Method(data);
+ Assert.Equal(42, data.i);
+ obj.MethodIn(in data);
+ Assert.Equal(42, data.i);
+ var oldData = data;
+ obj.MethodRef(ref data);
+ Assert.True(oldData == data); // We want reference equality here
+ obj.MethodOut(out data);
+ Assert.Equal(1, data.i);
+ Assert.Equal(1, obj.Return().i);
+ Assert.Equal(1, obj.ReturnPreserveSig().i);
+ }
+
public void ICollectionMarshallingFails()
{
Type hrExceptionType = SystemFindsComCalleeException() ? typeof(MarshallingFailureException) : typeof(Exception);
private TUnmanaged* _originalUnmanaged;
private TUnmanaged* _unmanaged;
private TManaged[] _managed;
+ private TUnmanaged* Unmanaged => _unmanaged == null ? _unmanaged = (TUnmanaged*)Marshal.AllocCoTaskMem(sizeof(TUnmanaged) * _managed.Length) : _unmanaged;
public void FromUnmanaged(TUnmanaged* unmanaged)
{
public TUnmanaged* ToUnmanaged()
{
- return _unmanaged = (TUnmanaged*)Marshal.AllocCoTaskMem(sizeof(TUnmanaged) * _managed.Length);
+ return Unmanaged;
}
public ReadOnlySpan<TManaged> GetManagedValuesSource()
public Span<TUnmanaged> GetUnmanagedValuesDestination()
{
- return new(_unmanaged, _managed.Length);
+ return new(Unmanaged, _managed.Length);
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
StatefulType ReturnPreserveSig();
}
+ [GeneratedComClass]
+ internal partial class StatefulMarshalling : IStatefulMarshalling
+ {
+ public void Method(StatefulType param) => param.i++;
+ public void MethodIn(in StatefulType param) => param.i++;
+ public void MethodOut(out StatefulType param) => param = new StatefulType() { i = 1 };
+ public void MethodRef(ref StatefulType param) { }
+ public StatefulType Return() => new StatefulType() { i = 1 };
+ public StatefulType ReturnPreserveSig() => new StatefulType() { i = 1 };
+ }
+
[NativeMarshalling(typeof(StatefulTypeMarshaller))]
internal class StatefulType
{
+ public int i;
+ }
+
+ internal struct StatefulNative
+ {
+ public int i;
}
[CustomMarshaller(typeof(StatefulType), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToUnmanaged))]
{
internal struct Bidirectional
{
+ public static int FreeCount { get; private set; }
+ StatefulType? _managed;
+ bool _hasManaged;
+ StatefulNative _unmanaged;
+ bool _hasUnmanaged;
+
public void FromManaged(StatefulType managed)
{
- throw new System.NotImplementedException();
+ _hasManaged = true;
+ _managed = managed;
}
- public nint ToUnmanaged()
+ public StatefulNative ToUnmanaged()
{
- throw new System.NotImplementedException();
+ if (!_hasManaged) throw new InvalidOperationException();
+ return new StatefulNative() { i = _managed.i };
}
- public void FromUnmanaged(nint unmanaged)
+ public void FromUnmanaged(StatefulNative unmanaged)
{
- throw new System.NotImplementedException();
+ _hasUnmanaged = true;
+ _unmanaged = unmanaged;
}
public StatefulType ToManaged()
{
- throw new System.NotImplementedException();
+ if (!_hasUnmanaged)
+ {
+ throw new InvalidOperationException();
+ }
+ if (_hasManaged && _managed.i == _unmanaged.i)
+ {
+ return _managed;
+ }
+ return new StatefulType() { i = _unmanaged.i };
}
public void Free()
{
- throw new System.NotImplementedException();
+ FreeCount++;
}
public void OnInvoked() { }
internal struct ManagedToUnmanaged
{
+ public static int FreeCount { get; private set; }
+ StatefulType? _managed;
+ bool _hasManaged;
public void FromManaged(StatefulType managed)
{
- throw new System.NotImplementedException();
+ _hasManaged = true;
+ _managed = managed;
}
- public nint ToUnmanaged()
+ public StatefulNative ToUnmanaged()
{
- throw new System.NotImplementedException();
+ if (!_hasManaged) throw new InvalidOperationException();
+ return new StatefulNative() { i = _managed.i };
}
public void Free()
{
- throw new System.NotImplementedException();
+ FreeCount++;
}
public void OnInvoked() { }
internal struct UnmanagedToManaged
{
- public void FromUnmanaged(nint unmanaged)
+ public static int FreeCount { get; private set; }
+ StatefulNative _unmanaged;
+ bool _hasUnmanaged;
+
+ public void FromUnmanaged(StatefulNative unmanaged)
{
- throw new System.NotImplementedException();
+ _hasUnmanaged = true;
+ _unmanaged = unmanaged;
}
public StatefulType ToManaged()
{
- throw new System.NotImplementedException();
+ if (!_hasUnmanaged)
+ {
+ throw new InvalidOperationException();
+ }
+ return new StatefulType() { i = _unmanaged.i };
}
public void Free()
{
- throw new System.NotImplementedException();
+ FreeCount++;
}
public void OnInvoked() { }
[ContiguousCollectionMarshaller]
[CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(StatelessCollectionMarshaller<,>.ManagedToUnmanaged))]
[CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.UnmanagedToManagedOut, typeof(StatelessCollectionMarshaller<,>.ManagedToUnmanaged))]
- [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementIn, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ManagedToUnmanagedOut, typeof(StatelessCollectionMarshaller<,>.UnmanagedToManaged))]
[CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.UnmanagedToManagedIn, typeof(StatelessCollectionMarshaller<,>.UnmanagedToManaged))]
- [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementOut, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.UnmanagedToManagedRef, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ManagedToUnmanagedRef, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementIn, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementOut, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(StatelessCollection<>), MarshalMode.ElementRef, typeof(StatelessCollectionMarshaller<,>.Bidirectional))]
internal static unsafe class StatelessCollectionMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
[CustomMarshaller(typeof(StatelessType), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToUnmanaged))]
[CustomMarshaller(typeof(StatelessType), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToUnmanaged))]
- [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementIn, typeof(Bidirectional))]
[CustomMarshaller(typeof(StatelessType), MarshalMode.ManagedToUnmanagedOut, typeof(UnmanagedToManaged))]
[CustomMarshaller(typeof(StatelessType), MarshalMode.UnmanagedToManagedIn, typeof(UnmanagedToManaged))]
[CustomMarshaller(typeof(StatelessType), MarshalMode.ElementOut, typeof(Bidirectional))]
+ [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementIn, typeof(Bidirectional))]
+ [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(StatelessType), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(StatelessType), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
- [CustomMarshaller(typeof(StatelessType), MarshalMode.ElementRef, typeof(Bidirectional))]
internal static class StatelessTypeMarshaller
{
public static int AllFreeCount => Bidirectional.FreeCount + UnmanagedToManaged.FreeCount + ManagedToUnmanaged.FreeCount;