Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3927921
Convert Buffer property to Buffer() method
Sergio0694 Feb 20, 2026
4b377da
Add WindowsRuntimeExternalArrayBuffer for external arrays
Sergio0694 Feb 20, 2026
b563d13
Add WindowsRuntimeExternalArrayBuffer marshaller
Sergio0694 Feb 20, 2026
a74dafb
Support WindowsRuntimeExternalArrayBuffer cases
Sergio0694 Feb 20, 2026
7c6f3ed
Flatten Windows.Storage.Streams paths
Sergio0694 Feb 21, 2026
f9eeb25
Use ThrowIfBufferLengthExceedsCapacity helper
Sergio0694 Feb 22, 2026
f230ec1
Add GetSpan to external and pinned buffers
Sergio0694 Feb 22, 2026
d2de7c1
Rename GetSpan to GetSpanForCapacity
Sergio0694 Feb 25, 2026
a2edded
Add IBuffer AsBuffer extensions for byte[]
Sergio0694 Feb 25, 2026
b3a44c0
Use Span for buffer capacity and add CopyTo
Sergio0694 Feb 25, 2026
0261ad6
Add byte[] CopyTo overloads and improve docs
Sergio0694 Feb 25, 2026
be42f2f
Add IBuffer-to-Span CopyTo overloads
Sergio0694 Feb 25, 2026
3b1b900
Add byte[] overloads for IBuffer.CopyTo
Sergio0694 Feb 25, 2026
676fec2
Add IBuffer CopyTo overloads and safety checks
Sergio0694 Feb 25, 2026
ab68af8
Add IBuffer.ToArray extension methods
Sergio0694 Feb 25, 2026
e598eb1
Add IsSameData and TryGetSpan helpers
Sergio0694 Feb 25, 2026
4081551
Add IBuffer.GetByte extension method
Sergio0694 Feb 25, 2026
64c8b6d
Add IBuffer-backed MemoryStream wrapper
Sergio0694 Feb 25, 2026
b6819d2
Add UnmanagedMemoryStream backed by IBuffer
Sergio0694 Feb 25, 2026
bab564b
Add GetArray and IBuffer AsStream helpers
Sergio0694 Feb 25, 2026
2636e1a
Use exception helpers for buffer checks
Sergio0694 Feb 25, 2026
e9f4fd4
Remove WindowsRuntimeBuffer and related files
Sergio0694 Feb 25, 2026
b1f0781
Fix typo
Sergio0694 Feb 25, 2026
c842d88
Fix typos
Sergio0694 Feb 25, 2026
fdecafb
Use BufferOffset exception message and add constant
Sergio0694 Feb 25, 2026
24d9534
Refactor IBuffer unwrap and access helpers
Sergio0694 Feb 26, 2026
28706d2
Remove unused usings in buffer extensions
Sergio0694 Feb 26, 2026
66dbe5d
Add Windows Buffers using; remove attribute
Sergio0694 Feb 26, 2026
989cb4c
Remove unused WindowsRuntime usings
Sergio0694 Feb 26, 2026
cbf1f96
Stub WindowsRuntimeBuffer handling with TODOs
Sergio0694 Feb 26, 2026
9da115c
Remove WindowsRuntime using; add Buffers namespace
Sergio0694 Feb 26, 2026
3312550
Merge branch 'staging/3.0' into user/sergiopedri/port-buffer-extensions
Sergio0694 Feb 28, 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
2 changes: 1 addition & 1 deletion src/Tests/FunctionalTests/Async/Program.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using TestComponentCSharp;
using Windows.Foundation;
using Windows.Foundation.Tasks;
using Windows.Storage.Buffers;
using Windows.Storage.Streams;
using Windows.Web.Http;
using WindowsRuntime.InteropServices;
Expand Down
1 change: 0 additions & 1 deletion src/Tests/ObjectLifetimeTests/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
Expand Down
1 change: 0 additions & 1 deletion src/Tests/ObjectLifetimeTests/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;

Expand Down
1 change: 0 additions & 1 deletion src/Tests/ObjectLifetimeTests/MyControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Microsoft.UI.Xaml;
Expand Down
1 change: 0 additions & 1 deletion src/Tests/ObjectLifetimeTests/ObjectLifetimePage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Microsoft.UI.Xaml;
Expand Down
2 changes: 1 addition & 1 deletion src/Tests/UnitTest/ApiCompatTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
using Windows.Data.Json;

using Windows.Storage;
using Windows.Storage.Buffers;
using Windows.Storage.Streams;
using Windows.Storage.FileProperties;

using System.Diagnostics;
using System.Runtime.InteropServices.WindowsRuntime;

namespace UnitTest
{
Expand Down
2 changes: 1 addition & 1 deletion src/Tests/UnitTest/TestComponentCSharp_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -36,6 +35,7 @@
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage;
using Windows.Storage.Buffers;
using Windows.Storage.Streams;
using Windows.UI;
using Windows.UI.Notifications;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using WindowsRuntime;
using WindowsRuntime.InteropServices;
using WindowsRuntime.InteropServices.Marshalling;
using static System.Runtime.InteropServices.ComWrappers;

#pragma warning disable CS0723, IDE0008, IDE0046, IDE1006

[assembly: TypeMapAssociation<WindowsRuntimeComWrappersTypeMapGroup>(
source: typeof(WindowsRuntimeExternalArrayBuffer),
proxy: typeof(ABI.WindowsRuntime.InteropServices.WindowsRuntimeExternalArrayBuffer))]

namespace ABI.WindowsRuntime.InteropServices;

/// <summary>
/// ABI type for <see cref="WindowsRuntimeExternalArrayBuffer"/>.
/// </summary>
[WindowsRuntimeClassName("Windows.Storage.Streams.IBuffer")]
[WindowsRuntimeExternalArrayBufferComWrappersMarshaller]
file static class WindowsRuntimeExternalArrayBuffer;

/// <summary>
/// The set of <see cref="ComInterfaceEntry"/> values for <see cref="WindowsRuntimeExternalArrayBuffer"/>.
/// </summary>
file struct WindowsRuntimeExternalArrayBufferInterfaceEntries
{
public ComInterfaceEntry IBuffer;
public ComInterfaceEntry IBufferByteAccess;
public ComInterfaceEntry IStringable;
public ComInterfaceEntry IWeakReferenceSource;
public ComInterfaceEntry IMarshal;
public ComInterfaceEntry IAgileObject;
public ComInterfaceEntry IInspectable;
public ComInterfaceEntry IUnknown;
}

/// <summary>
/// The implementation of <see cref="WindowsRuntimeExternalArrayBufferInterfaceEntries"/>.
/// </summary>
file static class WindowsRuntimeExternalArrayBufferInterfaceEntriesImpl
{
/// <summary>
/// The <see cref="WindowsRuntimeExternalArrayBufferInterfaceEntries"/> value for <see cref="WindowsRuntimeExternalArrayBuffer"/>.
/// </summary>
[FixedAddressValueType]
public static readonly WindowsRuntimeExternalArrayBufferInterfaceEntries Entries;

/// <summary>
/// Initializes <see cref="Entries"/>.
/// </summary>
static WindowsRuntimeExternalArrayBufferInterfaceEntriesImpl()
{
Entries.IBuffer.IID = WellKnownWindowsInterfaceIIDs.IID_IBuffer;
Entries.IBuffer.Vtable = Windows.Storage.Streams.IBufferImpl.Vtable;
Entries.IBufferByteAccess.IID = WellKnownWindowsInterfaceIIDs.IID_IBufferByteAccess;
Entries.IBufferByteAccess.Vtable = WindowsRuntimeExternalArrayBufferByteAccessImpl.Vtable;
Entries.IStringable.IID = WellKnownWindowsInterfaceIIDs.IID_IStringable;
Entries.IStringable.Vtable = IStringableImpl.Vtable;
Entries.IWeakReferenceSource.IID = WellKnownWindowsInterfaceIIDs.IID_IWeakReferenceSource;
Entries.IWeakReferenceSource.Vtable = IWeakReferenceSourceImpl.Vtable;
Entries.IMarshal.IID = WellKnownWindowsInterfaceIIDs.IID_IMarshal;
Entries.IMarshal.Vtable = IMarshalImpl.RoBufferVtable;
Entries.IAgileObject.IID = WellKnownWindowsInterfaceIIDs.IID_IAgileObject;
Entries.IAgileObject.Vtable = IAgileObjectImpl.Vtable;
Entries.IInspectable.IID = WellKnownWindowsInterfaceIIDs.IID_IInspectable;
Entries.IInspectable.Vtable = IInspectableImpl.Vtable;
Entries.IUnknown.IID = WellKnownWindowsInterfaceIIDs.IID_IUnknown;
Entries.IUnknown.Vtable = IUnknownImpl.Vtable;
}
}

/// <summary>
/// A custom <see cref="WindowsRuntimeComWrappersMarshallerAttribute"/> implementation for <see cref="WindowsRuntimeExternalArrayBuffer"/>.
/// </summary>
[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage,
DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId,
UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed unsafe class WindowsRuntimeExternalArrayBufferComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute
{
/// <inheritdoc/>
public override void* GetOrCreateComInterfaceForObject(object value)
{
// No reference tracking is needed, see notes in the marshaller attribute for 'WindowsRuntimePinnedArrayBuffer'
return (void*)WindowsRuntimeComWrappers.Default.GetOrCreateComInterfaceForObject(value, CreateComInterfaceFlags.None);
}

/// <inheritdoc/>
public override ComInterfaceEntry* ComputeVtables(out int count)
{
count = sizeof(WindowsRuntimeExternalArrayBufferInterfaceEntries) / sizeof(ComInterfaceEntry);

return (ComInterfaceEntry*)Unsafe.AsPointer(in WindowsRuntimeExternalArrayBufferInterfaceEntriesImpl.Entries);
}
}

/// <summary>
/// The native implementation of <c>IBufferByteAccess</c> for <see cref="WindowsRuntimeExternalArrayBuffer"/>.
/// </summary>
file static unsafe class WindowsRuntimeExternalArrayBufferByteAccessImpl
{
/// <summary>
/// The <see cref="IBufferByteAccessVftbl"/> value for the <see cref="WindowsRuntimeExternalArrayBuffer"/> implementation.
/// </summary>
[FixedAddressValueType]
private static readonly IBufferByteAccessVftbl Vftbl;

/// <summary>
/// Initializes <see cref="Vftbl"/>.
/// </summary>
static WindowsRuntimeExternalArrayBufferByteAccessImpl()
{
*(IInspectableVftbl*)Unsafe.AsPointer(ref Vftbl) = *(IInspectableVftbl*)IInspectableImpl.Vtable;

Vftbl.Buffer = &Buffer;
}

/// <summary>
/// Gets a pointer to the <see cref="WindowsRuntimeExternalArrayBuffer"/> implementation.
/// </summary>
public static nint Vtable
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => (nint)Unsafe.AsPointer(in Vftbl);
}

/// <see href="https://learn.microsoft.com/windows/win32/api/robuffer/nf-robuffer-ibufferbyteaccess-buffer"/>
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvMemberFunction)])]
private static HRESULT Buffer(void* thisPtr, byte** value)
{
if (value is null)
{
return WellKnownErrorCodes.E_POINTER;
}

try
{
var thisObject = ComInterfaceDispatch.GetInstance<global::WindowsRuntime.InteropServices.WindowsRuntimeExternalArrayBuffer>((ComInterfaceDispatch*)thisPtr);

*value = thisObject.Buffer();

return WellKnownErrorCodes.S_OK;
}
catch (Exception ex)
{
return RestrictedErrorInfoExceptionMarshaller.ConvertToUnmanaged(ex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ private static HRESULT Buffer(void* thisPtr, byte** value)
{
var thisObject = ComInterfaceDispatch.GetInstance<global::WindowsRuntime.InteropServices.WindowsRuntimePinnedArrayBuffer>((ComInterfaceDispatch*)thisPtr);

*value = thisObject.Buffer;
*value = thisObject.Buffer();

return WellKnownErrorCodes.S_OK;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Windows.Storage.Streams;

namespace WindowsRuntime.InteropServices;

/// <summary>
/// A <see cref="MemoryStream"/> implementation backed by a managed <see cref="IBuffer"/> instance.
/// </summary>
internal sealed class WindowsRuntimeBufferMemoryStream : MemoryStream
{
/// <summary>
/// The <see cref="IBuffer"/> instance to back the stream.
/// </summary>
private readonly IBuffer _buffer;

/// <summary>
/// Creates a new <see cref="WindowsRuntimeBufferMemoryStream"/> instance with the specified parameters.
/// </summary>
/// <param name="buffer">The <see cref="IBuffer"/> instance to back the stream.</param>
/// <param name="array">The byte array to use as the underlying storage.</param>
/// <param name="offset">The offset in the byte array where the stream starts.</param>
/// <remarks>This constructor doesn't validate any of its parameters.</remarks>
public WindowsRuntimeBufferMemoryStream(IBuffer buffer, byte[] array, int offset)
: base(array, offset, (int)buffer.Capacity, writable: true)
{
_buffer = buffer;

SetLength(buffer.Length);
}

/// <inheritdoc/>
public override void SetLength(long value)
{
base.SetLength(value);

// The input value is limited by 'Capacity', so this cast is safe
_buffer.Length = (uint)Length;
}

/// <inheritdoc/>
public override void Write(byte[] buffer, int offset, int count)
{
base.Write(buffer, offset, count);

_buffer.Length = (uint)Length;
}

/// <inheritdoc/>
public override void Write(ReadOnlySpan<byte> buffer)
{
base.Write(buffer);

_buffer.Length = (uint)Length;
}

/// <inheritdoc/>
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
await base.WriteAsync(buffer, offset, count, cancellationToken);

_buffer.Length = (uint)Length;
}

/// <inheritdoc/>
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
await base.WriteAsync(buffer, cancellationToken);

_buffer.Length = (uint)Length;
}

/// <inheritdoc/>
public override void WriteByte(byte value)
{
base.WriteByte(value);

_buffer.Length = (uint)Length;
}
}
Loading
Loading