Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,26 @@ public void TestTryGetDataUnsafe()
GC.KeepAlive(buf);
}

[Fact]
public void TestTryGetDataUnsafe_MemoryBufferReference()
{
var buffer = new Windows.Foundation.MemoryBuffer(256);
var reference = buffer.CreateReference();

Assert.True(WindowsRuntimeMarshal.TryGetDataUnsafe(reference, out IntPtr dataPtr1, out uint capacity1));
Assert.True(dataPtr1 != IntPtr.Zero);
Assert.True(capacity1 == 256);

Assert.True(WindowsRuntimeMarshal.TryGetDataUnsafe(reference, out IntPtr dataPtr2, out uint capacity2));
Assert.True(dataPtr2 != IntPtr.Zero);
Assert.True(capacity2 == 256);

Assert.True(dataPtr1 == dataPtr2);

// Ensure the reference doesn't get collected while we use the data pointer
GC.KeepAlive(reference);
}

[Fact]
public void TestBufferTryGetArray()
{
Expand Down
27 changes: 26 additions & 1 deletion src/WinRT.Runtime/Interop/IID.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,31 @@ public static ref readonly Guid IID_IBufferByteAccess
}
}

/// <summary>The IID for <c>IMemoryBufferByteAccess</c> (5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D).</summary>
public static ref readonly Guid IID_IMemoryBufferByteAccess
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ReadOnlySpan<byte> data = new byte[]
{
0x35, 0x32, 0x0D, 0x5B,
0xBA, 0x4D,
0x44, 0x4D,
0x86,
0x5E,
0x8F,
0x1D,
0x0E,
0x4F,
0xD0,
0x4D
};

return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
}
}

/// <summary>The IID for <c>IContextCallback</c> (000001DA-0000-0000-C000-000000000046).</summary>
internal static ref readonly Guid IID_IContextCallback
{
Expand Down Expand Up @@ -640,7 +665,7 @@ internal static ref readonly Guid IID_WUX_INotifyCollectionChangedEventArgs
}
}

/// <summary>The IID for <c>WUX_MotifyCollectionChangedEventHandler</c> (8B0909DC-2005-5D93-BF8A-725F017BAA8D).</summary>
/// <summary>The IID for <c>MUX_NotifyCollectionChangedEventHandler</c> (8B0909DC-2005-5D93-BF8A-725F017BAA8D).</summary>
internal static ref readonly Guid IID_MUX_NotifyCollectionChangedEventHandler
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
1 change: 1 addition & 0 deletions src/WinRT.Runtime/Interop/IID.tt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var entries = new (string Name, string IID, bool IsPublic)[]
("IMarshal", "00000003-0000-0000-C000-000000000046", true),
("IBuffer", "905A0FE0-BC53-11DF-8C49-001E4FC686DA", true),
("IBufferByteAccess", "905A0FEF-BC53-11DF-8C49-001E4FC686DA", true),
("IMemoryBufferByteAccess", "5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D", true),
("IContextCallback", "000001DA-0000-0000-C000-000000000046", false),
("ICallbackWithNoReentrancyToApplicationSTA", "0A299774-3E4E-FC42-1D9D-72CEE105CA57", false),
("IErrorInfo", "1CF2B120-547D-101B-8E65-08002B2BD119", false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ static partial class WindowsRuntimeMarshal
/// </summary>
/// <param name="buffer">The buffer to get the data pointer for.</param>
/// <param name="dataPtr">The pointer to the underlying data representation of the buffer.</param>
/// <returns>Whether the data was successfully retrieved.</returns>
/// <exception cref="Exception">Thrown if invoking <c>IBufferByteAccess::Buffer</c> on the input buffer fails.</exception>
public static unsafe bool TryGetDataUnsafe(
#if NET
[NotNullWhen(true)]
Expand Down Expand Up @@ -65,6 +67,51 @@ public static unsafe bool TryGetDataUnsafe(
return false;
}

/// <summary>
/// Returns a pointer to the underlying data representation of the <see cref="IMemoryBufferReference"/>.
/// Callers are responsible for ensuring that the buffer is kept alive while the pointer is in use.
/// </summary>
/// <param name="buffer">The buffer to get the data pointer for.</param>
/// <param name="dataPtr">The pointer to the underlying data representation of the buffer.</param>
/// <param name="capacity">The capacity of the buffer.</param>
/// <returns>Whether the data was successfully retrieved.</returns>
/// <exception cref="Exception">Thrown if invoking <c>IMemoryBufferByteAccess::Buffer</c> on the input buffer fails.</exception>
public static unsafe bool TryGetDataUnsafe(
#if NET
[NotNullWhen(true)]
#endif
IMemoryBufferReference? buffer, out IntPtr dataPtr, out uint capacity)
{
if (buffer == null)
{
dataPtr = IntPtr.Zero;
capacity = 0;
return false;
}

if (ComWrappersSupport.TryUnwrapObject(buffer, out var unwrapped) &&
unwrapped.TryAs(global::WinRT.Interop.IID.IID_IMemoryBufferByteAccess, out IntPtr ThisPtr) >= 0)
{
try
{
IntPtr __retval = default;
uint __capacity = 0;
global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, IntPtr*, uint*, int>**)ThisPtr)[3](ThisPtr, &__retval, &__capacity));
dataPtr = __retval;
capacity = __capacity;
return true;
}
finally
{
Marshal.Release(ThisPtr);
}
}

dataPtr = IntPtr.Zero;
capacity = 0;
return false;
}

/// <summary>
/// Tries to get an array segment from the underlying buffer. The return value indicates the success of the operation.
/// </summary>
Expand Down