C++ Direct2D ID2D1HwndRenderTarget 的父 IUnknown 类的_vfptr变量变为 null

C++ Direct2D ID2D1HwndRenderTarget's parent IUnknown class' _vfptr variable becomes null

本文关键字:变量 vfptr null 类的 Direct2D ID2D1HwndRenderTarget 的父 IUnknown C++      更新时间:2023-10-16

我有一个我正在制作的Direct2D应用程序,并且我正在编写一个Direct2D库,该库也使我更轻松地使用Direct2D。如果需要的话,我将发布确切的有问题的代码,但是我的主要问题是我在一个类的定义中有一个ID2D1HWNDRENDERDARGET,我将与另一个类扩展该类初始化渲染目标的父类,然后又调用子类的负载方法。但是,一旦该程序达到子类的负载内容方法,__vfptr变量(我不知道那是什么),在ID2D1HWNDRENDERDERTARGET的IUNKNOWN部分中,现在为无效。我觉得这一点的唯一原因是,在使用渲染目标从IwicbitMapsource创建ID2D1BITMAP时,我在其他一些代码中遇到了违规错误。我不明白这是怎么发生的,因为在初始化渲染目标后,_vfptr变量在初始化代码返回的方法后立即变为null。谁能解释为什么会发生这种情况?我的相关代码在下面。

此代码一次来创建HWND渲染目标和屏幕外渲染目标。这是在DLL项目中。gamebase.cpp

HRESULT GameBase::Initialize(HINSTANCE hInst, HWND winHandle, struct DX2DInitOptions options)
        {
            this->mainRenderTarget = NULL;
            this->offscreenRendTarget = NULL;
            this->factory = NULL;
            HRESULT result;
            D2D1_FACTORY_OPTIONS factOptions;
            D2D1_FACTORY_TYPE factType;
            if(options.enableDebugging)
                factOptions.debugLevel = D2D1_DEBUG_LEVEL::D2D1_DEBUG_LEVEL_ERROR;
            else
                factOptions.debugLevel = D2D1_DEBUG_LEVEL::D2D1_DEBUG_LEVEL_NONE;
            if(options.singleThreadedApp)
                factType = D2D1_FACTORY_TYPE_SINGLE_THREADED;
            else
                factType = D2D1_FACTORY_TYPE_MULTI_THREADED;
            result = D2D1CreateFactory(factType, factOptions, &this->factory);
            if(FAILED(result))
            {
                OutputDebugString(L"Failed to create a Direct 2D Factory!");
                return result;
            }
            this->instance = hInst;
            this->hwnd = winHandle;
            D2D1_SIZE_U size = D2D1::SizeU(options.winWidth, options.winHeight);
            this->width = options.winWidth;
            this->height = options.winHeight;
            result = factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(winHandle, size), &this->mainRenderTarget);
            if(FAILED(result))
            {
                OutputDebugString(L"Failed to create a render target to draw to the window with!");
                return result;
            }
            result = this->mainRenderTarget->CreateCompatibleRenderTarget(&this->offscreenRendTarget);
            if(FAILED(result))
            {
                OutputDebugString(L"Failed to create an offscreen render target from the main render target.");
                return result;
            }
            return LoadContent();
        }

在致电LoadContent之后,我绝不会更改MainrenderTarget的值。

dx2dimage.cpp

HRESULT DX2DImageLoader::LoadFromResource(LPCWSTR resourceName, LPCWSTR resourceType, HMODULE progModule, DX2DImage* image)
        {
            if(!this->isInit)
            {
                OutputDebugStringA("You must call InitializeImageLoader before using this image loader!");
                return E_FAIL;
            }
            IWICBitmapDecoder *decoder = NULL;
            IWICBitmapFrameDecode *source = NULL;
            IWICStream *stream = NULL;
            IWICFormatConverter *converter = NULL;
            HRSRC imageResHandle = NULL;
            HGLOBAL imageResDataHandle = NULL;
            void *imageFile = NULL;
            DWORD imageFileSize = 0;
            HRESULT result;

            //Find the image.
            imageResHandle = FindResource(progModule, resourceName, resourceType);
            if(!imageResHandle)
            {
                OutputDebugStringA("Failed to get a handle to the resource!");
                return E_FAIL;
            }
            //Load the data handle of the image.
            imageResDataHandle = LoadResource(progModule, imageResHandle);
            if(!imageResDataHandle)
            {
                OutputDebugStringA("Failed to load the image from the module!");
                return E_FAIL;
            }
            //Lock and retrieve the image.
            imageFile = LockResource(imageResDataHandle);
            if(!imageFile)
            {
                OutputDebugStringA("Failed to lock the image in the module!");
                return E_FAIL;
            }
            //Get the size of the image.
            imageFileSize = SizeofResource(progModule, imageResHandle);
            if(!imageFileSize)
            {
                OutputDebugStringA("Failed to retrieve the size of the image in the module!");
                return E_FAIL;
            }
            //Create a stream that will read the image data.
            result = this->factory->CreateStream(&stream);
            if(FAILED(result))
            {
                OutputDebugStringA("Failed to create an IWICStream!");
                return result;
            }
            //Open a stream to the image.
            result = stream->InitializeFromMemory(reinterpret_cast<BYTE*>(imageFile), imageFileSize);
            if(FAILED(result))
            {
                OutputDebugStringA("Failed to initialize the stream!");
                return result;
            }
            //Create a decoder from the stream
            result = this->factory->CreateDecoderFromStream(stream, NULL, WICDecodeMetadataCacheOnDemand, &decoder);
            if(FAILED(result))
            {
                OutputDebugStringA("Failed to create a decoder from the stream!");
                return result;
            }
            //Get the first frame from the image.
            result = decoder->GetFrame(0, &source);
            if(FAILED(result))
            {
                OutputDebugStringA("Failed to get the first frame from the decoder!");
                return result;
            }
            //Create a format converter to convert image to 32bppPBGRA
            result = this->factory->CreateFormatConverter(&converter);
            if(FAILED(result))
            {
                OutputDebugStringA("Failed to create a format converter!");
                return result;
            }
            //Convert the image to the new format.
            result = converter->Initialize(source, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeMedianCut);
            if(FAILED(result))
            {
                OutputDebugStringA("Failed to convert the image to the correct format!");
                return result;
            }
            //Create the Direct2D Bitmap from the Wic Bitmap.
            result = this->renderTarget->CreateBitmapFromWicBitmap(converter, NULL, &image->bitmap);
            if(FAILED(result))
            {
                OutputDebugStringA("Failed to create a Direct 2D Bitmap from a WIC Bitmap!");
                return result;
            }
            image->width = static_cast<UINT>(image->bitmap->GetSize().width);
            image->height = static_cast<UINT>(image->bitmap->GetSize().height);
            SafeRelease(&source);
            SafeRelease(&converter);
            SafeRelease(&decoder);
            SafeRelease(&stream);
            return S_OK;
        }

访问违规例外发生在线

result = this->renderTarget->CreateBitmapFromWicBitmap(converter, NULL, &image->bitmap);

其中image-> bitmap是当前的null(应该是应该是)ID2D1BITMAP。

在这里,RenderTarget变量是上面的gameBase.cpp的MainrenderTarget变量。当我调试线路时,所有rendertarget的父母都不是无效的,但是一旦我到达iunknown界面下方,_vfpptr的事情就无效了。转换器变量,此变量或图像变量并非如此。

我没有足够的代码来调试您的代码,但是从我看来,我怀疑converter->Initialize(...)的呼叫是无效的,因为MSDN说:

If you do not have a predefined palette, you must first create one. Use
InitializeFromBitmap to create the palette object, then pass it in along
with your other parameters. 
dither, pIPalette, alphaThresholdPercent, and paletteTranslate are used to
mitigate color loss when converting to a reduced bit-depth format. For
conversions that do not need these settings, the following parameters values
should be used: dither set to WICBitmapDitherTypeNone, pIPalette set to NULL,
alphaThresholdPercent set to 0.0f, and paletteTranslate set to
WICBitmapPaletteTypeCustom.

在您的代码中,您不提供有效的pallete(使用NULL),而您的 paletteTranslate 不是 wicbitmappalettetepepecustom