1

As part of a WinRT C++cx component, what's the most efficient way to convert an unmanaged buffer of bytes (say expressed as a std::string) back and forth with a Windows::Web::Http::HttpBufferContent?

This is what I ended up with, but it doesn't seem very optimal:

std::string to HttpBufferContent:

std::string m_body = ...;
auto writer = ref new DataWriter();
writer->WriteBytes(ArrayReference<unsigned char>(reinterpret_cast<unsigned char*>(const_cast<char*>(m_body.data())), m_body.length()));
auto content = ref new HttpBufferContent(writer->DetachBuffer());

HttpBufferContent to std::string:

HttpBufferContent^ content = ...
auto operation = content->ReadAsBufferAsync();
auto task = create_task(operation);
if (task.wait() == task_status::completed) {
    auto buffer = task.get();
    size_t length = buffer->Length;
    if (length > 0) {
        unsigned char* storage = static_cast<unsigned char*>(malloc(length));
        DataReader::FromBuffer(buffer)->ReadBytes(ArrayReference<unsigned char>(storage, length));
        auto m_body = std::string(reinterpret_cast<char*>(storage), length);
        free(storage);
    }
} else {
    abort();
}

UPDATE: Here's the version I ended up using (you can trivially create a HttpBufferContent^ from an Windows::Storage::Streams::IBuffer^):

void IBufferToString(IBuffer^ buffer, std::string& string) {
    Array<unsigned char>^ array = nullptr;
    CryptographicBuffer::CopyToByteArray(buffer, &array);  // TODO: Avoid copy
    string.assign(reinterpret_cast<char*>(array->Data), array->Length);
}

IBuffer^ StringToIBuffer(const std::string& string) {
    auto array = ArrayReference<unsigned char>(reinterpret_cast<unsigned char*>(const_cast<char*>(string.data())), string.length());
    return CryptographicBuffer::CreateFromByteArray(array);
}
Pol
  • 3,848
  • 1
  • 38
  • 55

2 Answers2

0

I think you are making at least one unnecessary copy of your data in your current approach for HttpBufferContent to std::string, you could improve this by accessing the IBuffer data directly, see the accepted answer here: Getting an array of bytes out of Windows::Storage::Streams::IBuffer

Community
  • 1
  • 1
yms
  • 10,361
  • 3
  • 38
  • 68
0

I think it's better to use smart pointer (no memory management needed) :

#include <wrl.h>
#include <robuffer.h>
#include <memory>
using namespace Windows::Storage::Streams;
using namespace Microsoft::WRL;

IBuffer^ buffer;
ComPtr<IBufferByteAccess> byte_access;
reinterpret_cast<IInspectable*>(buffer)->QueryInterface(IID_PPV_ARGS(&byte_access));
std::unique_ptr<byte[]> raw_buffer = std::make_unique<byte[]>(buffer->Length);
byte_access->Buffer(raw_buffer.get());
std::string str(reinterpret_cast<char*>(raw_buffer.get())); // just 1 copy
t.ouvre
  • 2,856
  • 1
  • 11
  • 17