【问题标题】:Do I need to AddRef() if returning pointer to pointer COM object from function?如果从函数返回指向指针 COM 对象的指针,我是否需要 AddRef()?
【发布时间】:2019-10-21 02:35:10
【问题描述】:

下面是一个将资源图像从可执行文件加载到ID2D1Bitmap指针的函数。

我的问题是,我需要在ID2D1Bitmap** ppBitmap函数参数上调用AddRef()吗?

例如在函数的末尾我需要这个吗:

(*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;
}

【问题讨论】:

  • 不,你不需要这样做。您最终只需返回 CreateBitmapFromWicBitmap 的结果
  • 不,CreateBitmapFromWicBitmap() 已经这样做了。因此,使用您的函数的代码中的单个 Release() 调用足以再次销毁它。
  • 你知道在什么情况下我需要AddRef() 吗?关于 AddRef 的任何规则
  • 一般Rules for Managing Reference Counts,但您需要了解自己的参考计数。还有Managing the Lifetime of an Object

标签: c++ winapi com


【解决方案1】:
hr = pRenderTarget->CreateBitmapFromWicBitmap(
        pConverter,
        0,
        ppBitmap);

成功调用上述CreateBitmapFromWicBitmap 方法返回的ID2D1Bitmap 对象,已经设置了正确的引用计数。所以,你不应该打电话给AddRef

您只需要在完成对象后在ID2D1Bitmap* COM 接口指针上调用Release

相反,如果你在返回的指针上再显式调用一次AddRef,你将需要一个适当的附加匹配Release调用,否则返回的对象不会释放自己.

请注意,由于我们讨论的是 C++ 代码(不是 C 代码),您可以简化所有这些 COM 接口指针生命周期管理代码,使用 智能 指针,如 @ 987654321@,而不是指向 COM 接口的原始指针。

CComPtr自动在包装的原始 COM 接口指针上调用 AddRefRelease(例如,在作用域的末尾,Release 将由 @987654335 调用@destructor),所以你不必关注这些 COM 对象的生命周期细节。此外,在异常情况下,Release 也会被自动调用,因此在抛出异常时不会泄漏 COM 对象。

【讨论】:

    猜你喜欢
    • 2013-04-10
    • 2019-04-14
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多