How to get access to WriteableBitmap.PixelBuffer pixels with C++?

c++-cx, com, windows-runtime, winrt-xaml

Solution

Your code is correct--the reference count on the `IBufferByteAccess` interface of `*buffer` is incremented by the call to `QueryInterface`, and you must call `Release` once to release that reference.

However, if you use `ComPtr<T>`, this becomes much simpler--with `ComPtr<T>`, you cannot call any of the three members of `IUnknown` (`AddRef`, `Release`, and `QueryInterface`); it prevents you from calling them. Instead, it encapsulates calls to these member functions in a way that makes it difficult to screw things up. Here's an example of how this would look:

// 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));

The call to `bufferInspectable.As(&bufferBytes)` performs a safe `QueryInterface`: it computes the IID from the type of `bufferBytes`, performs the `QueryInterface`, and attaches the resulting pointer to `bufferBytes`. When `bufferBytes` goes out of scope, it will automatically call `Release`. The code has the same effect as yours, but without the error-prone explicit resource management.

The example uses the following two utilities, which help to keep the code clean:

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);
}

Observant readers will notice that because this code uses a `ComPtr` for the `IInspectable*` we get from `buffer`, this code actually performs an additional `AddRef`/`Release` compared to the original code. I would argue that the chance of this impacting performance is minimal, and it's best to start from code that is easy to verify as correct, then optimize for performance once the hot spots are understood.

Problem

There are a lot of samples for C#, but only some code snippets for C++ on MSDN. I have put it together and I think it will work, but I am not sure if I am releasing all the COM references I have to.

Original source