为什么在析构函数中的IWICImagingFactory对象上调用继承的IUnknown :: Release()函数会导致在对象的虚函数表(__vfptr)中显示每个条目的“CXX0030:错误:表达式无法计算”? / p>
这是参考我之前发布的一个问题,但我已经意识到问题只发生在析构函数中。虚拟功能表在我检查过的任何其他地方都有效。但是,一旦在析构函数中,所有条目都显示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。
答案 0 :(得分:5)
我最近也在努力解决这个问题。问题是IWICImagingFactory
的创建和发布取决于分别在之前和之后调用CoInitialize
/ CoUninitialize
。在您的应用程序中,很可能在析构函数中释放CoUninitialize()
之前调用IWICImagingFactory
,这会导致崩溃。请注意ID2D1RenderTarget
等似乎没有受到影响,并且在调用CoUninitialize()
后仍然可以发布。
从CoUninitialize()
或其他任何地方删除对RunMessageLoop()
的调用,并在析构函数中的释放调用之后将其放入,崩溃应该消失。
答案 1 :(得分:1)
在构造函数或析构函数中调用虚函数不会调用您认为它将调用的函数。它总是导致调用同一个类的函数。
您可以假设在构造函数和析构函数中禁用了虚拟调度。
更恰当的说法是:
在执行构造函数或析构函数期间,对运行构造函数或析构函数的对象进行虚拟调用,就好像调用中使用的对象表达式的动态类型等于构造函数或析构函数的类一样。
礼貌:在C ++ Lounge中进行了长时间的讨论,最后,@ JohannesSchaublitb提出了这个恰当的定义,我们大多数人似乎都同意这一定义。