2012-05-09 12 views
8

Chcę zaimplementować C++ WinRT IBuffer, który owija bufor *, więc mogę go używać z operacjami WinRT WriteAsync/ReadAsync, które akceptują parametr IBuffer ^.Jak owinąć bufor char * w WinRT IBuffer w C++

EDIT 1 (wyjaśnienie)

chcę uniknąć kopiowania danych.

+0

Jeśli funkcja może mieć tablicę Ponadto, jest to alternatywna (i być może łatwiej) trasa: http://stackoverflow.com/a/16645877/588476 –

Odpowiedz

9

Głównie skopiowane z http://jeremiahmorrill.wordpress.com/2012/05/11/http-winrt-client-for-c/ ale przystosowany do bezpośredniego owinąć własną bajt []:

NativeBuffer.h:

#pragma once 

#include <wrl.h> 
#include <wrl/implements.h> 
#include <windows.storage.streams.h> 
#include <robuffer.h> 
#include <vector> 

// todo: namespace 

class NativeBuffer : 
    public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>, 
    ABI::Windows::Storage::Streams::IBuffer, 
    Windows::Storage::Streams::IBufferByteAccess> 
{ 
public: 
    virtual ~NativeBuffer() 
    { 
    } 

    STDMETHODIMP RuntimeClassInitialize(byte *buffer, UINT totalSize) 
    { 
     m_length = totalSize; 
     m_buffer = buffer; 

     return S_OK; 
    } 

    STDMETHODIMP Buffer(byte **value) 
    { 
     *value = m_buffer; 

     return S_OK; 
    } 

    STDMETHODIMP get_Capacity(UINT32 *value) 
    { 
     *value = m_length; 

     return S_OK; 
    } 

    STDMETHODIMP get_Length(UINT32 *value) 
    { 
     *value = m_length; 

     return S_OK; 
    } 

    STDMETHODIMP put_Length(UINT32 value) 
    { 
     m_length = value; 

     return S_OK; 
    } 

private: 
    UINT32 m_length; 
    byte *m_buffer; 
}; 

Aby utworzyć IBuffer:

Streams::IBuffer ^CreateNativeBuffer(LPVOID lpBuffer, DWORD nNumberOfBytes) 
{ 
    Microsoft::WRL::ComPtr<NativeBuffer> nativeBuffer; 
    Microsoft::WRL::Details::MakeAndInitialize<NativeBuffer>(&nativeBuffer, (byte *)lpBuffer, nNumberOfBytes); 
    auto iinspectable = (IInspectable *)reinterpret_cast<IInspectable *>(nativeBuffer.Get()); 
    Streams::IBuffer ^buffer = reinterpret_cast<Streams::IBuffer ^>(iinspectable); 

    return buffer; 
} 

a wezwanie do odczyt danych (lpBuffer to bajt []):

Streams::IBuffer ^buffer = CreateNativeBuffer(lpBuffer, nNumberOfbytes); 
create_task(randomAccessStream->ReadAsync(buffer, (unsigned int)nNumberOfBytesToRead, Streams::InputStreamOptions::None)).wait(); 

Nie jestem pewien, czy ComPtr potrzebuje czyszczenia, więc wszelkie sugestie dotyczące zarządzania pamięcią są mile widziane.

+0

'm_buffer = nowy bajt [totalSize]; "Widzę" nowy "; Nie widzę żadnego "delete". Byłoby dobrze zawinąć to tak, że gdy bazowy bufor zostanie zniszczony, przyszłe próby uzyskania dostępu do niego przez 'NativeBuffer' mogą się nie udać (jak to zrobić zależy od sposobu użycia). 'Reinterpret_cast' z' nativeBuffer.Get() 'na' IInspectable * 'powinno być niepotrzebne. –

+0

Tak, przykro mi, ta część nie powinna tam być. Zaktualizowałem odpowiedź, aby to odzwierciedlić, używając konstruktora COM, aby ustawić bajt [] tak jak powinien. – pfo

+0

Spróbuję tego rozwiązania, gdy znajdę jakiś czas, dzięki. –

5

To powinno działać:

// Windows::Storage::Streams::DataWriter 
// Windows::Storage::Streams::IBuffer 
// BYTE = unsigned char (could be char too) 
BYTE input[1024] {}; 

DataWriter ^writer = ref new DataWriter(); 
writer->WriteBytes(Platform::ArrayReference<BYTE>(input, sizeof(input)); 
IBuffer ^buffer = writer->DetachBuffer();