【问题标题】:following "What's a Creel?"s tutorial: Can't create a IWICBitmapDecoder, in visual studio 2015遵循“什么是纱架?”教程:无法在 Visual Studio 2015 中创建 IWICBitmapDecoder
【发布时间】:2016-10-31 14:29:23
【问题描述】:

我一直在关注“什么是纱架?”的直接 2d 教程。我到了教程 8:“加载图像”。我没有 spritesheet 对象保存指向 Graphics 对象的指针,因为这会导致此版本的 Visual Studio 出现问题,因此每次调用需要它的东西时都会通过。要点:当我尝试使用wicfactory->CreateDecoderFromFile() 方法创建IWICBitmapDecoder 时,出现以下错误:

在 Project8.exe 中的 0x008C70A7 处引发异常:0xC0000005:访问冲突读取位置 0x00000000。

在我得到的汽车中:

hr | E_NOINTERFACE No such interface supported. this | 0x00c1a5c8 {bmp=0x00000000 <NULL> } spritesheet * wicfactory | 0x00000000<NULL> wicdecoder | 0xcccccccc{...}

代码是这样的:

#pragma once

#include <wincodec.h>   //include windowscodecs.lib in the linker input
#include "Graphics.h"
#include <d2d1.h>
#include<string>

class spritesheet {
public:

    ID2D1Bitmap* bmp;
    spritesheet() {}

    spritesheet(LPCWSTR file, graphics* gfx) {
        //this->gfx = gfx;
        //bmp = NULL;
        HRESULT hr;
        //create an image factory
        IWICImagingFactory *wicFactory;
        hr = CoCreateInstance(
            CLSID_WICImagingFactory,
            NULL,
            CLSCTX_INPROC_SERVER,
            CLSID_WICImagingFactory,
            (LPVOID*)&wicFactory
            );

        //create a decoder
        IWICBitmapDecoder *wicdecoder;
        hr = wicFactory->CreateDecoderFromFilename(
            file,
            NULL,
            GENERIC_READ,
            WICDecodeMetadataCacheOnLoad,
            &wicdecoder
            );
        IWICBitmapFrameDecode* wicframe = NULL;
        hr = wicdecoder->GetFrame(0, &wicframe);

        IWICFormatConverter *wicconverter = NULL;
        hr = wicFactory->CreateFormatConverter(&wicconverter);

        hr = wicconverter->Initialize(
            wicframe,
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            NULL,
            0.0,
            WICBitmapPaletteTypeCustom
            );

        gfx->gettarget()->CreateBitmapFromWicBitmap(
            wicconverter,
            NULL,
            &bmp
            );

        if (wicdecoder) wicdecoder->Release();
        if (wicFactory) wicFactory->Release();
        if (wicconverter) wicconverter->Release();
        if (wicframe) wicframe->Release();

    }

    void init(wchar_t * file, graphics * gfx) {
        //this->gfx = gfx;
        //bmp = NULL;
        HRESULT hr;
        //create an image factory
        IWICImagingFactory* wicFactory;
        hr = CoCreateInstance(
            CLSID_WICImagingFactory,
            NULL,
            CLSCTX_INPROC_SERVER,
            CLSID_WICImagingFactory,
            (LPVOID*)&wicFactory
            );

        //create a decoder
        IWICBitmapDecoder* wicdecoder;
        hr = wicFactory->CreateDecoderFromFilename(
            file,
            NULL,
            GENERIC_READ,
            WICDecodeMetadataCacheOnLoad,
            &wicdecoder
            );

        IWICBitmapFrameDecode* wicframe = NULL;
        hr = wicdecoder->GetFrame(0, &wicframe);

        IWICFormatConverter *wicconverter = NULL;
        hr = wicFactory->CreateFormatConverter(&wicconverter);

        hr = wicconverter->Initialize(
            wicframe,
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            NULL,
            0.0,
            WICBitmapPaletteTypeCustom
            );

        gfx->rendertarget->CreateBitmapFromWicBitmap(
            wicconverter,
            NULL,
            &bmp
            );

        if (wicdecoder) wicdecoder->Release();
        if (wicFactory) wicFactory->Release();
        if (wicconverter) wicconverter->Release();
        if (wicframe) wicframe->Release();

        gfx->rendertarget->DrawBitmap(
            bmp,
            D2D1::RectF(0.0f, 0.0f, 10, 10),        //dest rect
            1.0f,
             D2D1_BITMAP_INTERPOLATION_MODE::D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,  //effect for scaling
        D2D1::RectF(0, 0, 10, 10));             //scource rect


}


void draw(graphics *gfx) {
    gfx->rendertarget->DrawBitmap(
        bmp,
        D2D1::RectF(0.0f, 0.0f, 10, 10),        //dest rect
        1.0f,
        D2D1_BITMAP_INTERPOLATION_MODE::D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,  //effect for scaling
        D2D1::RectF(0, 0, 10, 10));             //scource rect

    }
};

现在,只是为了测试一下,我确实在每个方法的开头放了一个 ID2D1Bitmap* bmp; 只是为了看看事情发生在哪里,但是 wicdecoder 错误消息只是更改为内存中的一个随机位置。

【问题讨论】:

  • 您没有正确使用 CoCreateInstance()。使用正确的接口 guid,IID_IWICImagingFactory。并添加错误检查,这样您就不会一直耕作,直到它因随机异常而崩溃。
  • 你能举例说明我在这种情况下如何使用 CoCreateInstance() 吗?我对此有点陌生,我想知道老手将如何实施它

标签: c++ visual-studio-2015 direct2d wic


【解决方案1】:

发现问题。 CoCreateInstance() 的实现很好,但他的代码存在一些问题,与它过时有关。

现在,在我开始之前,我必须说,这部分摘自:https://msdn.microsoft.com/en-us/library/windows/desktop/dd756686(v=vs.85).aspx

这里的实现仍然没有提供CoCreateInstance() 的可用实现,(并且还要求您拥有this 教程的样板代码。此外,教程的代码来自2008 年,架构扩展了应用程序的内存量每次调整窗口大小时都使用...但我离题了。要点:不要将该教程的程序示例用作您自己的程序的模型,但它确实提供了一个很好的示例,说明如何声明/初始化正确的 WIC 和D2D 对象)DX12 的 Microsoft 文档也已过时,但我将在此澄清。

CoCreateInstance()的正确实现,以及加载图片的正确方法是:

void spritesheet::load(PCWSTR uri, ID2D1HwndRenderTarget * gfx) {

    IWICBitmapDecoder *pDecoder = NULL;
    IWICBitmapFrameDecode *pSource = NULL;
    IWICStream *pStream = NULL;
    IWICFormatConverter *pConverter = NULL;
    IWICBitmapScaler *pScaler = NULL;


    IWICImagingFactory *wicFactory = NULL;

    CoCreateInstance(
        CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWICImagingFactory,
        (LPVOID*)&wicFactory);

    HRESULT hr = wicFactory->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 = wicFactory->CreateFormatConverter(&pConverter);

    }


    if (SUCCEEDED(hr)) {
        hr = pConverter->Initialize(
            pSource,
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            NULL,
            0.f,
            WICBitmapPaletteTypeMedianCut
            );
    }
    if (SUCCEEDED(hr))
    {

        // Create a Direct2D bitmap from the WIC bitmap.
        hr = gfx->CreateBitmapFromWicBitmap(
            pConverter,
            NULL,
            &bmp
            );
    }

    if (pDecoder) {
        pDecoder->Release();
    }
    if (pSource) {
        pSource->Release();

    }
    if (pConverter) {
        pConverter->Release();
    }
}

注意: uri 只是文件名,采用 PCWSTR 格式,在传递给函数时声明为 L"name.bmp"

正确的画图方法是:

void spritesheet::draw(ID2D1HwndRenderTarget * gfx, float bx, float by, float rx, float ry, float dx, float dy) {

    D2D1_SIZE_F size = bmp->GetSize();
    D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(dx, dy);

    gfx->DrawBitmap(
        bmp,
        D2D1::RectF(
            upperLeftCorner.x,
            upperLeftCorner.y,
            upperLeftCorner.x + rx,
            upperLeftCorner.y + ry),
        1,
        D2D1_BITMAP_INTERPOLATION_MODE::D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
        D2D1::RectF(
            bx,
            by,
            rx,
            ry)
        );
}

现在,D2D 文档的其余部分不是最新的,但仍然为您提供了一个很好的示例来说明可以使用的内容。一些对象不再存在,例如 D2D1::Rect 被罐头,现在您只有:D2D1::RectF,并且一些文档和教程相当杂乱无章且未经测试,但如果您挖掘足够长的时间,您可以创建一个游戏。只记得让 x86/x64 可再发行包作为用 c# 编写的安装程序的一部分运行(因为 c++ 不再在 Windows 中本地运行,而 c# 的速度只有一半),你的 c++ 程序将在你需要的地方运行.

【讨论】:

    【解决方案2】:

    我正在尝试执行您在此处提供的解决方案,但没有运气仍然 wicFactory 为空。

    D2DGauge* d2dg = reinterpret_cast<D2DGauge*>(args);
    HRESULT hr;
    bmp = nullptr;
    
    IWICBitmapDecoder *pDecoder = NULL;
    IWICBitmapFrameDecode *pSource = NULL;
    IWICFormatConverter *pConverter = NULL;
    
    //Creating a factory
    IWICImagingFactory *wicFactory = NULL;
    CoCreateInstance(
        CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWICImagingFactory,
        (LPVOID*)&wicFactory);
    
    MessageBox(NULL, (LPCWSTR)wicFactory, NULL, MB_OK);
    
    //Creating a decoder
    
    hr = wicFactory->CreateDecoderFromFilename(
        filename,
        NULL,
        GENERIC_READ,
        WICDecodeMetadataCacheOnLoad,
        &pDecoder);
    
    //Read Frame from image
    if (SUCCEEDED(hr)) {
        // Create the initial frame.
        hr = pDecoder->GetFrame(0, &pSource);
    }
    
    //Creating a Converter
    if (SUCCEEDED(hr)) {
    
        // Convert the image format to 32bppPBGRA
        // (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
        hr = wicFactory->CreateFormatConverter(&pConverter);
    }
    
    //Setup the converter
    if (SUCCEEDED(hr)) {
        hr = pConverter->Initialize(
            pSource,
            GUID_WICPixelFormat32bppPBGRA,
            WICBitmapDitherTypeNone,
            NULL,
            0.f,
            WICBitmapPaletteTypeMedianCut
        );
    }
    //Use the converter to create an D2D1Bitmap
    //ID2D1Bitmap* bmp;
    if (SUCCEEDED(hr))
    {
        hr = d2dg->pRT->CreateBitmapFromWicBitmap(
            pConverter,
            NULL,
            &bmp
        );
    }
    
    if (wicFactory)wicFactory->Release();
    if (pDecoder)pDecoder->Release();
    if (pConverter)pConverter->Release();
    if (pSource)pSource->Release();
    

    我怎样才能让它不是 nullptr?

    【讨论】:

    • 这应该作为一个单独的问题而不是作为一个旧问题的答案提出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多