C# 的示例很多,但 MSDN 上只有一些 C++ 的代码片段。我已经把它放在一起,我认为它会起作用,但我不确定我是否要发布我必须发布的所有 COM 引用。
3 回答
您的代码是正确的 -IBufferByteAccess
接口上的引用计数*buffer
通过对 的调用而增加QueryInterface
,并且您必须调用Release
一次以释放该引用。
但是,如果您使用ComPtr<T>
,这将变得更加简单——使用ComPtr<T>
,您不能调用IUnknown
( AddRef
、Release
和QueryInterface
) 的三个成员中的任何一个;它会阻止你打电话给他们。相反,它以一种难以搞砸的方式封装对这些成员函数的调用。这是一个外观示例:
// Get the buffer from the WriteableBitmap:
IBuffer^ buffer = bitmap->PixelBuffer;
// Convert from C++/CX to the ABI IInspectable*:
ComPtr<IInspectable> bufferInspectable(AsInspectable(buffer));
// Get the IBufferByteAccess interface:
ComPtr<IBufferByteAccess> bufferBytes;
ThrowIfFailed(bufferInspectable.As(&bufferBytes));
// Use it:
byte* pixels(nullptr);
ThrowIfFailed(bufferBytes->Buffer(&pixels));
bufferInspectable.As(&bufferBytes)
对执行安全的调用QueryInterface
:它根据 的类型计算 IID bufferBytes
,执行QueryInterface
,并将结果指针附加到bufferBytes
。当bufferBytes
超出范围时,它会自动调用Release
. 该代码与您的代码具有相同的效果,但没有容易出错的显式资源管理。
该示例使用以下两个实用程序,有助于保持代码整洁:
auto AsInspectable(Object^ const object) -> Microsoft::WRL::ComPtr<IInspectable>
{
return reinterpret_cast<IInspectable*>(object);
}
auto ThrowIfFailed(HRESULT const hr) -> void
{
if (FAILED(hr))
throw Platform::Exception::CreateException(hr);
}
细心的读者会注意到,由于这段代码使用 aComPtr
表示IInspectable*
我们从中得到的,因此与原始代码相比buffer
,这段代码实际上执行了一个额外的AddRef
/ 。Release
我认为这种影响性能的可能性很小,最好从易于验证是否正确的代码开始,然后在了解热点后优化性能。
这是我到目前为止所尝试的:
// Get the buffer from the WriteableBitmap
IBuffer^ buffer = bitmap->PixelBuffer;
// Get access to the base COM interface of the buffer (IUnknown)
IUnknown* pUnk = reinterpret_cast<IUnknown*>(buffer);
// Use IUnknown to get the IBufferByteAccess interface of the buffer to get access to the bytes
// This requires #include <Robuffer.h>
IBufferByteAccess* pBufferByteAccess = nullptr;
HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess));
if (FAILED(hr))
{
throw Platform::Exception::CreateException(hr);
}
// Get the pointer to the bytes of the buffer
byte *pixels = nullptr;
pBufferByteAccess->Buffer(&pixels);
// *** Do the work on the bytes here ***
// Release reference to IBufferByteAccess created by QueryInterface.
// Perhaps this might be done before doing more work with the pixels buffer,
// but it's possible that without it - the buffer might get released or moved
// by the time you are done using it.
pBufferByteAccess->Release();
当使用C++/WinRT(而不是 C++/CX)时,有一个更方便(也更危险)的替代方案。语言投影在将 a 返回到内存缓冲区的接口data()
上生成一个辅助函数。IBuffer
uint8_t*
假设它bitmap
是WriteableBitmap类型,则可以将代码缩减为:
uint8_t* pixels{ bitmap.PixelBuffer().data() };
// *** Do the work on the bytes here ***
// No cleanup required; it has already been dealt with inside data()'s implementation
在代码pixels
中是指向由bitmap
实例控制的数据的原始指针。因此,它仅在bitmap
活着的情况下才有效,但代码中没有任何内容可以帮助编译器(或阅读器)跟踪该依赖关系。
作为参考,文档中有一个示例说明WriteableBitmap::PixelBuffer
了(否则未记录的)辅助函数的使用data()
。