15

I have an object that implements the interface Windows::Storage::Streams::IBuffer, and I want to get an array of bytes out of it, however while looking at the documentation this interface looks pretty useless, and the documentation does not offer any reference to any other class that could be combined with this interface to achieve my purpose. All I have found so far with google is a reference to the .Net class WindowsRuntimeBufferExtensions but I am using C++ so this is also a dead end.

Can someone give a hint on how to get an array of bytes from Windows::Storage::Streams::IBuffer in C++?

Alam Brito
  • 463
  • 1
  • 4
  • 15

7 Answers7

12

You can use IBufferByteAccess, through exotic COM casts:

byte* GetPointerToPixelData(IBuffer^ buffer)
{
   // Cast to Object^, then to its underlying IInspectable interface.

   Object^ obj = buffer;
   ComPtr<IInspectable> insp(reinterpret_cast<IInspectable*>(obj));

   // Query the IBufferByteAccess interface.
   ComPtr<IBufferByteAccess> bufferByteAccess;
   ThrowIfFailed(insp.As(&bufferByteAccess));

   // Retrieve the buffer data.

   byte* pixels = nullptr;
   ThrowIfFailed(bufferByteAccess->Buffer(&pixels));

   return pixels;

}

Code sample copied from http://cm-bloggers.blogspot.fi/2012/09/accessing-image-pixel-data-in-ccx.html

Berthier Lemieux
  • 3,785
  • 1
  • 25
  • 25
  • I changed my implementation and I am using this approach now since it improves the performance of my app. Thanks. – Alam Brito Feb 01 '13 at 20:28
9

This is a C++/CX version:

std::vector<unsigned char> getData( ::Windows::Storage::Streams::IBuffer^ buf )
{
    auto reader = ::Windows::Storage::Streams::DataReader::FromBuffer(buf);

    std::vector<unsigned char> data(reader->UnconsumedBufferLength);

    if ( !data.empty() )
        reader->ReadBytes(
            ::Platform::ArrayReference<unsigned char>(
                &data[0], data.size()));

    return data;
}

For more information see Array and WriteOnlyArray (C++/CX).

Simon P Stevens
  • 27,303
  • 5
  • 81
  • 107
Petr Kalny
  • 91
  • 1
  • 1
9

Also check this method:

IBuffer -> Platform::Array
CryptographicBuffer.CopyToByteArray

Platform::Array -> IBuffer
CryptographicBuffer.CreateFromByteArray

As a side note, if you want to create Platform::Array from simple C++ array you could use Platform::ArrayReference, for example:

char* c = "sdsd";
Platform::ArrayReference<unsigned char> arraywrapper((unsigned char*) c, sizeof(c));
Wayne Uroda
  • 5,025
  • 4
  • 30
  • 35
Tommy
  • 91
  • 1
  • 1
5

As mentioned before, WindowsRuntimeBufferExtensions from the namespace System::Runtime::InteropServices::WindowsRuntime is only available for .Net applications and not for native C++ applications.

A possible solution would be to use Windows::Storage::Streams::DataReader:

void process(Windows::Storage::Streams::IBuffer^ uselessBuffer)
{
    Windows::Storage::Streams::DataReader^ uselessReader =
             Windows::Storage::Streams::DataReader::FromBuffer(uselessBuffer);
    Platform::Array<Byte>^ managedBytes = 
                         ref new Platform::Array<Byte>(uselessBuffer->Length);
    uselessReader->ReadBytes( managedBytes );                               
    BYTE * bytes = new BYTE[uselessBuffer->Length];
    for(int i = 0; i < uselessBuffer->Length; i++)
        bytes[i] = managedBytes[i];

    (...)
}
Alam Brito
  • 463
  • 1
  • 4
  • 15
4

Since this question is tagged , here's a solution using C++/WinRT. It essentially does the same as this answer under the hood, but is way more accessible. The (undocumented) data() helper on the IBuffer projection does all the heavy lifting:

uint8_t* GetPointerToPixelData(::winrt::Windows::Storage::Streams::IBuffer const& buffer)
{
    return buffer.data();
}

There is unfortunately no official documentation (yet), and I only stumbled across this in the sample code for the WritableBitmap.PixelBuffer property (make sure to select "C++/WinRT" from the language dropdown at the top right).

An identical solution (by explicitly querying for the IBufferByteAccess interface) is also available from that documentation entry when selecting "C++/CX" from the language dropdown.


Update 2022-10-15

Since writing this answer the documentation has been updated. The winrt namespace documentation now has a section called C++/WinRT functions that extend Windows Runtime APIs that lists Windows Runtime types alongside the C++/WinRT functions available in addition to the interface projections.

The IBuffer C++/WinRT extension functions link takes you to the respective section in the IBuffer interface documentation, with the data() function properly documented.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
3

This should work with WinRT extensions:

// Windows::Storage::Streams::DataReader
// buffer is assumed to be of type Windows::Storage::Streams::IBuffer
// BYTE = unsigned char

DataReader^ reader = DataReader::FromBuffer(buffer);

BYTE *extracted = new BYTE[buffer->Length];

// NOTE: This will read directly into the allocated "extracted" buffer
reader->ReadBytes(Platform::ArrayReference<BYTE>(extracted, buffer->Length));

// ... do something with extracted...

delete [] extracted; // don't forget to free the space
Robin R
  • 1,037
  • 10
  • 6
  • There is almost no documentation about this class Platform::ArrayReference, where did you find this information if I may ask? – Alam Brito Mar 23 '15 at 13:48
  • 2
    Here's an example from MSDN https://msdn.microsoft.com/en-us/library/hh700131.aspx "Use ArrayReference to avoid copying data" – Robin R Apr 10 '15 at 13:45
-1

Use the extension method like a static method:

IBuffer *buffer;
array<unsigned char>^ result= System::Runtime::InteropServices::WindowsRuntime::WindowsRuntimeBufferExtensions::ToArray(buffer);
Community
  • 1
  • 1
MSN
  • 53,214
  • 7
  • 75
  • 105
  • @user787913, I was confused at first as well. – MSN Aug 07 '12 at 22:28
  • 7
    @MSN WindowsRuntimeBufferExtensions is a class in .Net framework, it cannot be used from a native C++ application – yms Aug 08 '12 at 13:39