user11157650
user11157650

Reputation:

Do I need to AddRef() if returning pointer to pointer COM object from function?

Below is a function that loads resource image from executable into ID2D1Bitmap pointer.

My question is, do I need to call AddRef() on ID2D1Bitmap** ppBitmap function parameter?

for example at the end of the function do I need this:

(*ppBitmap)->AddRef();

I see code around internet do such call sometimes, sometimes not but I'm unable to understand when this is valid and when not?

Note: For minimum compilable code I provide whole function, excluding error checking implementation.

#include <sdkddkver.h>
#include <Windows.h>
#include <wincodec.h>   // WIC
#include <d2d1.h>       // ID2D1Bitmap

//
// Loads resource Image from executable
// into ID2D1Bitmap* pointer
//
template<typename RenderType>
HRESULT LoadResourceImage(
    IWICImagingFactory* pFactory,
    PCTSTR szFilename,
    PCTSTR szFileType,
    RenderType* pRenderTarget,
    ID2D1Bitmap** ppBitmap)
{
    HRESULT hr = S_OK;
    DWORD dwImageSize = 0;
    HMODULE hModule = GetModuleHandle(nullptr);

    HRSRC hResource = nullptr;
    HGLOBAL hResourceData = nullptr;
    void* pImageFile = nullptr;
    IWICStream* pStream = nullptr;
    IWICFormatConverter* pConverter = nullptr;
    IWICBitmapFrameDecode* pFrameDecode = nullptr;
    IWICBitmapDecoder* pDecoder = nullptr;

    if (!hModule)
    {
        ShowError(__FILENAME__, __LINE__);
        goto done;
    }

    hResource = FindResource(hModule, szFilename, szFileType);
    if (!hResource)
    {
        ShowError(__FILENAME__, __LINE__);
        goto done;
    }

    if (FAILED(hr = hResource ? S_OK : E_FAIL))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    dwImageSize = SizeofResource(hModule, hResource);
    if (!dwImageSize)
    {
        ShowError(__FILENAME__, __LINE__);
        goto done;
    }

    if (FAILED(hr = dwImageSize ? S_OK : E_FAIL))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    hResourceData = LoadResource(hModule, hResource);
    if (!hResourceData)
    {
        ShowError(__FILENAME__, __LINE__);
        goto done;
    }

    if (FAILED(hr = hResourceData ? S_OK : E_FAIL))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    pImageFile = LockResource(hResourceData);
    if (!pImageFile)
    {
        ShowError(__FILENAME__, __LINE__);
        goto done;
    }

    if (FAILED(hr = pImageFile ? S_OK : E_FAIL))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    if (FAILED(hr = pFactory->CreateStream(&pStream)))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    hr = pStream->InitializeFromMemory(
        reinterpret_cast<BYTE*>(pImageFile), dwImageSize);

    if (FAILED(hr))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    hr = pFactory->CreateDecoderFromStream(
        pStream,
        nullptr,
        WICDecodeMetadataCacheOnDemand,
        &pDecoder);

    if (FAILED(hr))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    if (FAILED(hr = pDecoder->GetFrame(0, &pFrameDecode)))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    if (FAILED(hr = pFactory->CreateFormatConverter(&pConverter)))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    hr = pConverter->Initialize(
        pFrameDecode,
        GUID_WICPixelFormat32bppPRGBA,
        WICBitmapDitherTypeNone,
        nullptr,
        0.f,
        WICBitmapPaletteTypeCustom);

    if (FAILED(hr))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

    hr = pRenderTarget->CreateBitmapFromWicBitmap(
        pConverter,
        0,
        ppBitmap);

    if (FAILED(hr))
    {
        ShowError(__FILENAME__, __LINE__, hr);
        goto done;
    }

done:
    SafeRelease(&pFrameDecode);
    SafeRelease(&pDecoder);
    SafeRelease(&pConverter);
    SafeRelease(&pStream);

    return hr;
}

Upvotes: 1

Views: 359

Answers (1)

Mr.C64
Mr.C64

Reputation: 42984

hr = pRenderTarget->CreateBitmapFromWicBitmap(
        pConverter,
        0,
        ppBitmap);

The ID2D1Bitmap object returned by successful calls of the CreateBitmapFromWicBitmap method above, already has a proper reference count set. So, you shouldn't call AddRef on it.

You only need to invoke Release on the ID2D1Bitmap* COM interface pointer when you're done with the object.

On the contrary, if you explicitly invoke AddRef one more time on the returned pointer, you will need a proper additional matching Release call, or the returned object won't free itself.

Note that, since we are discussing C++ code (not C code), you can simplify all this COM interface pointer life-cycle management code using smart pointers like ATL::CComPtr, instead of raw pointers to COM interfaces.

CComPtr will automatically invoke AddRef and Release on the wrapped raw COM interface pointers (for example, at the end of scope, Release will be invoked by the ~CComPtr destructor), so you don't have to pay attention to these COM object life-time details. Moreover, also in case of exceptions, Release will be invoked automatically as well, so you won't leak COM objects when exceptions are thrown.

Upvotes: 1

Related Questions