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

-2

I've been following "what's a Creel?"'s tutorial for direct 2d. I got to tutorial 8: 'Loading an image'. I didn't have the spritesheet object save the pointer to the Graphics object as this caused problems with this version of visual studio, so it's passed every time something needing it is called. main point: when I try creating a IWICBitmapDecoder with the wicfactory->CreateDecoderFromFile() method, I get the following error:

Exception thrown at 0x008C70A7 in Project8.exe: 0xC0000005: Access violation reading location 0x00000000.

and in the Autos I get:

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

the code being this:

#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

    }
};

now, just to test things, I did put a ID2D1Bitmap* bmp; at the start of each method just to see where things got, but the wicdecoder error message just changed to a random place in memory.

c++
visual-studio-2015
direct2d
wic
asked on Stack Overflow Jun 29, 2016 by mrsamsir • edited Aug 15, 2017 by Cœur

2 Answers

1

Found the issue. the implementation of CoCreateInstance() was fine, but there were a few problems with his code, relating to it being outdated.

NOW, before i begin, i must say, this was PARTLY taken from: https://msdn.microsoft.com/en-us/library/windows/desktop/dd756686(v=vs.85).aspx

the implementation here still gives no usable implementation of CoCreateInstance(), (and also requires you to have the boilerplate code of this tutorial. Also, the tutorial's code is from 2008 and the architecture expands the amount of memory the app uses every time you resize the window... but i digress. main point: DON'T use that tutorial's program example as a model for your own programs, but it does give a good example on how to declare/initialize the proper WIC and D2D objects) the Microsoft documentation for DX12 is also out of date, but this is what I will clarify here.

the correct implementation of CoCreateInstance(), and the correct way to load an image is:

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();
    }
}

Note: uri simply being the file name, in a PCWSTR format, declared as L"name.bmp" when passing to the function.

the correct way to draw an image is:

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)
        );
}

Now, the rest of the D2D documentation is not up to date, but still gives you a good example of what's out there to use. Some of the objects don't exist anymore, like D2D1::Rect being canned and now you only have: D2D1::RectF, nad some of the documentation and tutorials are rather disjointed and untested, but if you dig long enough, you can create a game. just remember to have the x86/x64 redistributeable packages run as part of your installer written in c# (because c++ won't run natively in windows anymore, and c# is half as fast), and your c++ program will run where you need it to.

answered on Stack Overflow Jul 16, 2016 by mrsamsir
0

Im tring to do the solution you gave here but no luck still wicFactory is null.

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();

How could I make it not a nullptr?

answered on Stack Overflow Nov 25, 2019 by Itay

User contributions licensed under CC BY-SA 3.0