Нужно ли AddRef (), если возвращать указатель на COM-объект указателя из функции? - PullRequest
1 голос
/ 05 июня 2019

Ниже приведена функция, которая загружает образ ресурса из исполняемого файла в указатель ID2D1Bitmap.

У меня вопрос: нужно ли вызывать AddRef() для ID2D1Bitmap** ppBitmap параметра функции?

например, в конце функции мне нужно это:

(*ppBitmap)->AddRef();

Я вижу, что код в Интернете иногда делает такой вызов, иногда нет, но я не могу понять, когда это действительно, а когда нет?

Примечание: для минимально компилируемого кода я предоставляю целую функцию, исключая реализацию проверки ошибок.

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

1 Ответ

1 голос
/ 05 июня 2019
hr = pRenderTarget->CreateBitmapFromWicBitmap(
        pConverter,
        0,
        ppBitmap);

Объект ID2D1Bitmap, возвращенный успешными вызовами метода CreateBitmapFromWicBitmap, описанного выше, уже имеет правильный установленный счетчик ссылок. Итак, вы не должны звонить AddRef.

Вы должны вызывать Release на указателе интерфейса ID2D1Bitmap* COM, только когда закончите с объектом.

Напротив, если вы явно вызовете AddRef еще раз для возвращаемого указателя, вам понадобится правильный дополнительный соответствующий Release вызов, иначе возвращаемый объект не освободится сам.

Обратите внимание, что, поскольку мы обсуждаем код C ++ (не код C), вы можете упростить весь этот код управления жизненным циклом указателя интерфейса COM, используя smart указатели типа ATL::CComPtr, вместо необработанных указателей на интерфейсы COM.

CComPtr автоматически вызовет AddRef и Release для указателей обернутого необработанного COM-интерфейса (например, в конце области действия Release будет вызываться ~CComPtr деструктор), так что вам не нужно обращать внимание на эти детали жизни COM-объекта. Более того, в случае исключений Release также будет вызываться автоматически, поэтому вы не будете пропускать COM-объекты при возникновении исключений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...