1

为什么在析构函数中对 IWICImagingFactory 对象调用继承的 IUnknown::Release() 函数会导致在对象的虚函数表 (__vfptr) 中显示“CXX0030:错误:无法评估表达式”?

这是参考我之前发布的一个问题,但我已经意识到问题只发生在析构函数中。虚函数表在我检查过的其他任何地方都有效。但是,一旦在析构函数中,所有条目都会显示 CXX0030 错误,并且尝试调用继承的 IUknown::Release() 失败。

编辑:这是一些演示代码:

HRESULT DemoApp::CreateDeviceIndependentResources()
{
HRESULT hr;


hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &mpDirect2DFactory);


if (SUCCEEDED(hr))
{
    hr = CoCreateInstance(
        CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&mpWICFactory)
        );
}

//CoCreateInstance returns S_OK.
//Other unrelated code here.
}

HRESULT DemoApp::CreateDeviceResources()
{
HRESULT hr;
//Other unrelated code here for creating device-dependant resources.
//mpBackgroundBitmap is a ID2D1Bitmap*.
    if(SUCCEEDED(hr))
    {
        hr = LoadBitmapFromFile(
            mpRenderTarget,
            mpWICFactory,
            L".\\background.png",
            0,
            0,
            &mpBackgroundBitmap);
    }
}


//The below LoadBitmapFromFile() code is taken directly from an MSDN sample.
//I didn't write it.

HRESULT DemoApp::LoadBitmapFromFile(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR uri,
UINT destinationWidth,
UINT destinationHeight,
ID2D1Bitmap **ppBitmap
)
{
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pSource = NULL;
IWICStream *pStream = NULL;
IWICFormatConverter *pConverter = NULL;
IWICBitmapScaler *pScaler = NULL;

HRESULT hr = pIWICFactory->CreateDecoderFromFilename(
    uri,
    NULL,
    GENERIC_READ,
    WICDecodeMetadataCacheOnLoad,
    &pDecoder
    );

if (SUCCEEDED(hr))
{
    // Create the initial frame.
    hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{

    // Convert the image format to 32bppPBGRA
    // (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
    hr = pIWICFactory->CreateFormatConverter(&pConverter);

}


if (SUCCEEDED(hr))
{
    // If a new width or height was specified, create an
    // IWICBitmapScaler and use it to resize the image.
    if (destinationWidth != 0 || destinationHeight != 0)
    {
        UINT originalWidth, originalHeight;
        hr = pSource->GetSize(&originalWidth, &originalHeight);
        if (SUCCEEDED(hr))
        {
            if (destinationWidth == 0)
            {
                FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
                destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
            }
            else if (destinationHeight == 0)
            {
                FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
                destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
            }

            hr = pIWICFactory->CreateBitmapScaler(&pScaler);
            if (SUCCEEDED(hr))
            {
                hr = pScaler->Initialize(
                        pSource,
                        destinationWidth,
                        destinationHeight,
                        WICBitmapInterpolationModeCubic
                        );
            }
            if (SUCCEEDED(hr))
            {
                hr = pConverter->Initialize(
                    pScaler,
                    GUID_WICPixelFormat32bppPBGRA,
                    WICBitmapDitherTypeNone,
                    NULL,
                    0.f,
                    WICBitmapPaletteTypeMedianCut
                    );
            }
        }
    }
    else // Don't scale the image.
    { 
        hr = pConverter->Initialize(
            pSource,
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            NULL,
            0.f,
            WICBitmapPaletteTypeMedianCut
            );
    }
}
if (SUCCEEDED(hr))
{

    // Create a Direct2D bitmap from the WIC bitmap.
    hr = pRenderTarget->CreateBitmapFromWicBitmap(
        pConverter,
        NULL,
        ppBitmap
        );
}

SafeRelease(&pDecoder);
SafeRelease(&pSource);
SafeRelease(&pStream);
SafeRelease(&pConverter);
SafeRelease(&pScaler);

return hr;
}

//Now I call SafeRelease() in my destructor and the virtual function table entires are showing the error.
DemoApp::~DemoApp()
{
SafeRelease(&mpDirect2DFactory);
SafeRelease(&mpWICFactory); //here is the problem apparently
SafeRelease(&mpDWriteFactory); 
SafeRelease(&mpRenderTarget);
SafeRelease(&mpBackgroundBitmap);

}

//SafeRelease is defined as:
template<class Interface>
inline void SafeRelease(Interface** ppInterfaceToRelease)
{
if(*ppInterfaceToRelease != NULL)
{
    (*ppInterfaceToRelease)->Release();
    (*ppInterfaceToRelease) = NULL;
        }

}

问题是当我在 WICFactory 对象上调用 SafeRelease() 时,我得到:DemoApp.exe 中 0x0024e135 处的第一次机会异常:0xC0000005:访问冲突读取位置 0x6d5c28f0。DemoApp.exe 中 0x0024e135 处的未处理异常:0xC0000005:访问冲突读取位置 0x6d5c28f0。

4

2 回答 2

5

我最近也为这个问题而苦苦挣扎。问题是创建和释放IWICImagingFactory依赖于CoInitialize/CoUninitialize分别在之前和之后被调用。在您的应用程序中,它很可能在析构函数中释放CoUninitialize()之前被调用,这会导致崩溃。IWICImagingFactory请注意,ID2D1RenderTarget和这样的似乎并没有受到影响,并且仍然可以在CoUninitialize()被调用后释放。

删除对CoUninitialize()fromRunMessageLoop()或任何位置的调用,并将其放在析构函数中的 release 调用之后,崩溃应该消失。

于 2012-06-13T12:01:02.930 回答
1

Calling virtual functions inside the constructor or destructor does not call the function you assume it will call. It always results in call to the functions of that same class.

You can assume virtual dispatch is disabled in constructor and destructors.

An more appropriate way of saying this is:

During the execution of a constructor or destructor, virtual calls on the object for which the constructor or destructor is run behave as if the dynamic type of the object expression used in the call is equal to the class of the constructor or destructor.

Courtesy: A lengthy discussion in C++ Lounge, Where finally, @JohannesSchaublitb came up with this apt definition, which most of us seemed to agree on.

于 2011-10-03T07:20:55.267 回答