Вызов унаследованного IUnknown :: Release () в деструкторе - PullRequest
1 голос
/ 03 октября 2011

Почему вызов унаследованной функции IUnknown :: Release () для объекта IWICImagingFactory в деструкторе приводит к тому, что «CXX0030: Ошибка: выражение не может быть оценено» отображается для каждой записи в таблице виртуальных функций объекта (__vfptr)?

Это относится к предыдущему вопросу, который я опубликовал, но с тех пор я понял, что проблема возникает только в деструкторе. Таблица виртуальных функций кажется действительной везде, где я проверял. Однако, как только в деструкторе все записи показаны с ошибкой 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;
        }

}

Проблема в том, что когда я вызываю SafeRelease () для объекта WICFactory, я получаю: Исключение первого шанса в 0x0024e135 в DemoApp.exe: 0xC0000005: расположение чтения нарушения доступа 0x6d5c28f0. Необработанное исключение в 0x0024e135 в DemoApp.exe: 0xC0000005: Место чтения нарушения доступа 0x6d5c28f0.

Ответы [ 2 ]

5 голосов
/ 13 июня 2012

В последнее время я тоже боролся с этой проблемой.Проблема в том, что создание и выпуск IWICImagingFactory зависит от CoInitialize / CoUninitialize, вызываемого до и после, соответственно.В вашем приложении вполне вероятно, что CoUninitialize() вызывается до того, как в деструкторе будет выпущено IWICImagingFactory, что вызовет сбой.Обратите внимание, что ID2D1RenderTarget и тому подобное, похоже, не затрагиваются и все еще могут быть освобождены после вызова CoUninitialize().

Удалите вызов CoUninitialize() из RunMessageLoop() или где бы он ни находился и поместите его послевызов освобождения в деструкторе и крах должны исчезнуть.

1 голос
/ 03 октября 2011

Вызов виртуальных функций внутри конструктора или деструктора не вызывает функцию, которую вы предполагаете вызвать.Это всегда приводит к вызову функций того же класса.

Можно предположить, что виртуальная диспетчеризация отключена в конструкторе и деструкторах.

Более подходящий способ сказать это:

Во времявыполнение конструктора или деструктора, виртуальные вызовы объекта, для которого запускается конструктор или деструктор, ведут себя так, как будто динамический тип выражения объекта, используемого в вызове, равен классу конструктора или деструктора.

Вежливость: длительная дискуссия в C ++ Lounge, где, наконец, @JohannesSchaublitb придумал это подходящее определение, с которым большинство из нас, похоже, согласились.

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