Skip to content

Commit d71f2d3

Browse files
authored
Add 'TryGetDataUnsafe' overload for 'IMemoryBufferReference' (#1673)
* Add 'IMemoryBufferReference' interop API * Add unit test
1 parent 9285dc8 commit d71f2d3

File tree

4 files changed

+94
-1
lines changed

4 files changed

+94
-1
lines changed

src/Tests/UnitTest/TestComponentCSharp_Tests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,26 @@ public void TestTryGetDataUnsafe()
482482
GC.KeepAlive(buf);
483483
}
484484

485+
[Fact]
486+
public void TestTryGetDataUnsafe_MemoryBufferReference()
487+
{
488+
var buffer = new Windows.Foundation.MemoryBuffer(256);
489+
var reference = buffer.CreateReference();
490+
491+
Assert.True(WindowsRuntimeMarshal.TryGetDataUnsafe(reference, out IntPtr dataPtr1, out uint capacity1));
492+
Assert.True(dataPtr1 != IntPtr.Zero);
493+
Assert.True(capacity1 == 256);
494+
495+
Assert.True(WindowsRuntimeMarshal.TryGetDataUnsafe(reference, out IntPtr dataPtr2, out uint capacity2));
496+
Assert.True(dataPtr2 != IntPtr.Zero);
497+
Assert.True(capacity2 == 256);
498+
499+
Assert.True(dataPtr1 == dataPtr2);
500+
501+
// Ensure the reference doesn't get collected while we use the data pointer
502+
GC.KeepAlive(reference);
503+
}
504+
485505
[Fact]
486506
public void TestBufferTryGetArray()
487507
{

src/WinRT.Runtime/Interop/IID.g.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,31 @@ public static ref readonly Guid IID_IBufferByteAccess
290290
}
291291
}
292292

293+
/// <summary>The IID for <c>IMemoryBufferByteAccess</c> (5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D).</summary>
294+
public static ref readonly Guid IID_IMemoryBufferByteAccess
295+
{
296+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
297+
get
298+
{
299+
ReadOnlySpan<byte> data = new byte[]
300+
{
301+
0x35, 0x32, 0x0D, 0x5B,
302+
0xBA, 0x4D,
303+
0x44, 0x4D,
304+
0x86,
305+
0x5E,
306+
0x8F,
307+
0x1D,
308+
0x0E,
309+
0x4F,
310+
0xD0,
311+
0x4D
312+
};
313+
314+
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
315+
}
316+
}
317+
293318
/// <summary>The IID for <c>IContextCallback</c> (000001DA-0000-0000-C000-000000000046).</summary>
294319
internal static ref readonly Guid IID_IContextCallback
295320
{
@@ -640,7 +665,7 @@ internal static ref readonly Guid IID_WUX_INotifyCollectionChangedEventArgs
640665
}
641666
}
642667

643-
/// <summary>The IID for <c>WUX_MotifyCollectionChangedEventHandler</c> (8B0909DC-2005-5D93-BF8A-725F017BAA8D).</summary>
668+
/// <summary>The IID for <c>MUX_NotifyCollectionChangedEventHandler</c> (8B0909DC-2005-5D93-BF8A-725F017BAA8D).</summary>
644669
internal static ref readonly Guid IID_MUX_NotifyCollectionChangedEventHandler
645670
{
646671
[MethodImpl(MethodImplOptions.AggressiveInlining)]

src/WinRT.Runtime/Interop/IID.tt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ var entries = new (string Name, string IID, bool IsPublic)[]
3333
("IMarshal", "00000003-0000-0000-C000-000000000046", true),
3434
("IBuffer", "905A0FE0-BC53-11DF-8C49-001E4FC686DA", true),
3535
("IBufferByteAccess", "905A0FEF-BC53-11DF-8C49-001E4FC686DA", true),
36+
("IMemoryBufferByteAccess", "5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D", true),
3637
("IContextCallback", "000001DA-0000-0000-C000-000000000046", false),
3738
("ICallbackWithNoReentrancyToApplicationSTA", "0A299774-3E4E-FC42-1D9D-72CEE105CA57", false),
3839
("IErrorInfo", "1CF2B120-547D-101B-8E65-08002B2BD119", false),

src/cswinrt/strings/additions/Windows.Storage.Streams/WindowsRuntimeMarshal.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ static partial class WindowsRuntimeMarshal
2727
/// </summary>
2828
/// <param name="buffer">The buffer to get the data pointer for.</param>
2929
/// <param name="dataPtr">The pointer to the underlying data representation of the buffer.</param>
30+
/// <returns>Whether the data was successfully retrieved.</returns>
31+
/// <exception cref="Exception">Thrown if invoking <c>IBufferByteAccess::Buffer</c> on the input buffer fails.</exception>
3032
public static unsafe bool TryGetDataUnsafe(
3133
#if NET
3234
[NotNullWhen(true)]
@@ -65,6 +67,51 @@ public static unsafe bool TryGetDataUnsafe(
6567
return false;
6668
}
6769

70+
/// <summary>
71+
/// Returns a pointer to the underlying data representation of the <see cref="IMemoryBufferReference"/>.
72+
/// Callers are responsible for ensuring that the buffer is kept alive while the pointer is in use.
73+
/// </summary>
74+
/// <param name="buffer">The buffer to get the data pointer for.</param>
75+
/// <param name="dataPtr">The pointer to the underlying data representation of the buffer.</param>
76+
/// <param name="capacity">The capacity of the buffer.</param>
77+
/// <returns>Whether the data was successfully retrieved.</returns>
78+
/// <exception cref="Exception">Thrown if invoking <c>IMemoryBufferByteAccess::Buffer</c> on the input buffer fails.</exception>
79+
public static unsafe bool TryGetDataUnsafe(
80+
#if NET
81+
[NotNullWhen(true)]
82+
#endif
83+
IMemoryBufferReference? buffer, out IntPtr dataPtr, out uint capacity)
84+
{
85+
if (buffer == null)
86+
{
87+
dataPtr = IntPtr.Zero;
88+
capacity = 0;
89+
return false;
90+
}
91+
92+
if (ComWrappersSupport.TryUnwrapObject(buffer, out var unwrapped) &&
93+
unwrapped.TryAs(global::WinRT.Interop.IID.IID_IMemoryBufferByteAccess, out IntPtr ThisPtr) >= 0)
94+
{
95+
try
96+
{
97+
IntPtr __retval = default;
98+
uint __capacity = 0;
99+
global::WinRT.ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, IntPtr*, uint*, int>**)ThisPtr)[3](ThisPtr, &__retval, &__capacity));
100+
dataPtr = __retval;
101+
capacity = __capacity;
102+
return true;
103+
}
104+
finally
105+
{
106+
Marshal.Release(ThisPtr);
107+
}
108+
}
109+
110+
dataPtr = IntPtr.Zero;
111+
capacity = 0;
112+
return false;
113+
}
114+
68115
/// <summary>
69116
/// Tries to get an array segment from the underlying buffer. The return value indicates the success of the operation.
70117
/// </summary>

0 commit comments

Comments
 (0)