0

我正在制作一个 Direct2D 应用程序,并且我正在编写一个 Direct2D 库,它也使我使用 Direct2D 更容易。如果需要,我将发布确切的有问题的代码,但我的主要问题是我在一个类的定义中有一个 ID2D1HwndRenderTarget,我用另一个类扩展了该类,在子类中我有一个调用方法的方法初始化Render Target的父类,然后依次调用子类的load方法。但是,一旦程序到达子类的加载内容方法,ID2D1HwndRenderTarget 的 IUnknown 部分中的 __vfptr 变量(我不知道那是什么)现在为空。我发现这一点的唯一原因是在其他一些代码中,当使用渲染目标从 IWicBitmapSource 创建 ID2D1Bitmap 时,我遇到了访问冲突错误。我不明白这是怎么发生的,因为在初始化渲染目标之后,只要带有初始化代码的方法返回,_vfptr 变量就会变为空。谁能解释为什么会发生这种情况?我的相关代码如下。

此代码被调用一次以创建 hwnd 渲染目标和离屏渲染目标。这是在一个 dll 项目中。游戏基础.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;
        }

线路发生Access Violation异常

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

其中 image->bitmap 是当前为 NULL(就像它应该是)ID2D1Bitmap。

这里,renderTarget 变量与上面 GameBase.cpp 中的 mainRenderTarget 变量相同。当我调试该行时,RenderTarget 的所有父级都不为空,但是一旦我到达它下面的 IUnknown 接口,_vfptr 的东西就是空的。对于转换器变量、此变量或图像变量,情况并非如此。

4

1 回答 1

0

我没有足够的代码来调试您的代码,但从我所看到的情况来看,我怀疑调用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.

并且在您的代码中,您没有提供有效的调色板(您使用过NULL)并且您的paletteTranslate不是WICBitmapPaletteTypeCustom

于 2012-10-28T23:02:41.213 回答