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問題は、依存の作成と解放がCoInitializeCoUninitializeそれぞれ前後に呼び出されることです。アプリケーションでは、デストラクタで が解放さCoUninitialize()れる前に が呼び出される可能性があり、クラッシュが発生します。and such は影響を受けないようで、が呼び出された後でも解放できることにIWICImagingFactory注意してください。ID2D1RenderTargetCoUninitialize()

CoUninitialize()fromRunMessageLoop()またはどこにでも呼び出しを削除し、デストラクタの release 呼び出しの後に配置すると、クラッシュは解消されます。

于 2012-06-13T12:01:02.930 に答える
1

コンストラクタまたはデストラクタ内で仮想関数を呼び出しても、呼び出すと想定している関数は呼び出されません。その結果、常に同じクラスの関数が呼び出されます。

コンストラクタとデストラクタで仮想ディスパッチが無効になっていると想定できます。

これを言うより適切な方法は次のとおりです。

コンストラクタまたはデストラクタの実行中、コンストラクタまたはデストラクタが実行されるオブジェクトに対する仮想呼び出しは、呼び出しで使用されるオブジェクト式の動的型がコンストラクタまたはデストラクタのクラスと等しいかのように動作します。

礼儀:C ++ラウンジでの長い議論で、ついに@JohannesSchaublitbがこの適切な定義を思いついたのですが、これは私たちのほとんどが同意しているようです。

于 2011-10-03T07:20:55.267 に答える