[MS] How do I create a Windows Runtime IRandom­Access­Stream around a bunch of bytes or a classic COM IStream? - devamazonaws.blogspot.com

There are some Windows Runtime methods which expect a random access stream in the form of a IRandom­Access­Stream. On the other hand, you might have your data in the form of a memory block. For example, you might have a memory block that represents a bitmap, and you want to wrap it in a IRandom­Access­Stream so you can use it as a Svg­Image­Source.

One option is to create an In­Memory­Random­Access­Stream and use the Write­Async() method to write the bytes (in the form of an IBuffer), then rewind the stream back to the start.

// C++/WinRT

winrt::Buffer BufferFromBytes(winrt::array_view<uint8_t> bytes)
{
    winrt::Buffer buffer(bytes.size());
    memcpy(buffer.data(), bytes.data(), bytes.size());
    buffer.Length(bytes.size());
    return buffer;
}

winrt::IAsyncOperation<winrt::IRandomAccessStream>
    BytesToRandomAccessStream(winrt::array_view<uint8_t> bytes)
{
    winrt::InMemoryRandomAccessStream stream;
    co_await stream.WriteAsync(BufferFromBytes(bytes));

    stream.Seek(0);
    co_return stream;
}

This is rather annoying because WriteAsync() is an async method, which means we have to co_await it, which in turn forces us to be a coroutine as well.

But there's a shortcut: Create­Random­Access­Stream­Over­Stream.

The Create­Random­Access­Stream­Over­Stream function takes a classic COM IStream and creates a Windows Runtime IRandom­Access­Stream around it.

So this will actually take two steps. First we need to put the bytes into an IStream. Then we can wrap the IStream inside an IRandom­Access­Stream.

// C++/WinRT

winrt::com_ptr<IStream> StreamFromBytes(winrt::array_view<uint8_t> bytes)
{
    winrt::com_ptr<IStream> stream{
        SHCreateMemStream(reinterpret_cast<const BYTE*>(bytes.data()),
                          bytes.size()),
        winrt::take_ownership_from_abi };
    winrt::check_pointer(stream.get());
    return stream;
}

winrt::IRandomAccessStream
    BytesToRandomAccessStream(winrt::array_view<uint8_t> bytes)
{
    return winrt::capture<winrt::IRandomAccessStream>(
        CreateRandomAccessStreamOverStream,
        StreamFromBytes(bytes).get(),
        BSOS_DEFAULT);
}

Bonus reading: The difference between assignment and attachment with ATL smart pointers, exacerbated by SHCreate­Mem­Stream not following standard COM patterns.

For C#, somebody did part of the work for you: Windows­Runtime­Stream­Extensions.As­Random­Access­Stream converts a System.IO.Stream to a Windows Runtime IRandom­Access­Stream.

// C#
IRandomAccessStream
    BytesToRandomAccessStream(byte* bytes, long length)
{
    var stream = new UnmanagedMemoryStream(bytes, length);
    return stream.AsRandomAccessStream();
}

The above function looks simple, but it's also dangerous because you don't know when it's safe to free the bytes. We can copy them into a Memory­Stream so that its lifetime is properly managed.

// C#
MemoryStream
    StreamFromBytes(byte* bytes, int length)
{
    var stream = new MemoryStream(length);
    stream.Write(new ReadOnlySpan<byte>(bytes, length));
    stream.Seek(0, SeekOrigin.Begin);
    return stream;
}

IRandomAccessStream
    BytesToRandomAccessStream(byte* bytes, int length)
{
    return StreamFromBytes(bytes, length).AsRandomAccessStream();
}

Post Updated on October 23, 2024 at 03:00PM
Thanks for reading
from devamazonaws.blogspot.com

Comments

Popular posts from this blog

Scenarios capability now generally available for Amazon Q in QuickSight - devamazonaws.blogspot.com

Research and Engineering Studio on AWS Version 2024.08 now available - devamazonaws.blogspot.com

Amazon EC2 C6id instances are now available in AWS Europe (Paris) region - devamazonaws.blogspot.com