以下 "What's a Creel?" 教程:无法在 visual studio 2015 年创建 IWICBitmapDecoder

following "What's a Creel?"s tutorial: Can't create a IWICBitmapDecoder, in visual studio 2015

我一直在关注 "what's a Creel?" 的直接 2d 教程。我学习了教程 8:'Loading an image'。我没有让 spritesheet 对象保存指向 Graphics 对象的指针,因为这会导致此版本的 visual studio 出现问题,因此每次调用需要它的东西时都会传递它。要点:当我尝试使用 wicfactory->CreateDecoderFromFile() 方法创建 IWICBitmapDecoder 时,出现以下错误:

Exception thrown at 0x008C70A7 in Project8.exe: 0xC0000005: Access violation reading location 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() 的实现很好,但是他的代码有一些问题,与它已经过时有关。

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

这里的实现仍然没有提供 CoCreateInstance() 的可用实现,(还需要你有 this 教程的样板代码。另外,教程的代码来自 2008 年,架构扩展每次调整 window 大小时应用程序使用的内存量...但我离题了。要点:不要使用该教程的程序示例作为您自己程序的模型,但它确实提供了一个很好的示例关于如何 declare/initialize 正确的 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++ 程序将 运行 在你需要它的地方。

我正在尝试执行您在此处提供的解决方案,但运气不佳,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?