Reputation:
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
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