我希望实现一个C++ WinRT的IBuffer,将char*缓冲区包装起来,这样我就可以将其与接受IBuffer^参数的WinRT WriteAsync/ReadAsync操作一起使用。
注1:我希望避免数据复制。
注1:我希望避免数据复制。
大部分内容来自http://jeremiahmorrill.wordpress.com/2012/05/11/http-winrt-client-for-c/,但经过改编以直接包装我的byte[]:
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;
};
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;
}
读取数据的调用(lpBuffer是字节数组):
Streams::IBuffer ^buffer = CreateNativeBuffer(lpBuffer, nNumberOfbytes);
create_task(randomAccessStream->ReadAsync(buffer, (unsigned int)nNumberOfBytesToRead, Streams::InputStreamOptions::None)).wait();
我不确定ComPtr是否需要清理,因此欢迎提出与内存管理相关的任何建议。
m_buffer = new byte[totalSize];
我看到了 new
,但没有看到任何 delete
。最好将其封装起来,这样当底层缓冲区被销毁时,通过 NativeBuffer
访问它的未来尝试将失败(如何实现取决于它的使用方式)。nativeBuffer.Get()
到 IInspectable*
的 reinterpret_cast
应该是不必要的。 - James McNellis(IInspectable *)reinterpret_cast<IInspectable *>(...);
是多余的。可以摆脱 C 风格的转换,因为 reinterpret_cast
已经执行了 C 风格的转换所做的操作,并且结果类型已经正确。 - Merlyn Morgan-Graham
// 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();