2

I met this problem when writing a minesweeper game. I used bitmap for numbers, mines and blanks. I think I have registered them correctly in the resource file

IDI_0                   BITMAP                  "D:\\User\\Mark\\Documents\\C++\\win32\\MineSweeper\\MineSweeper\\empty.bmp"
IDI_1                   BITMAP                  "D:\\User\\Mark\\Documents\\C++\\win32\\MineSweeper\\MineSweeper\\1.bmp"
IDI_2                   BITMAP                  "D:\\User\\Mark\\Documents\\C++\\win32\\MineSweeper\\MineSweeper\\2.bmp"
IDI_3                   BITMAP                  "D:\\User\\Mark\\Documents\\C++\\win32\\MineSweeper\\MineSweeper\\3.bmp"

and the header file

#define IDI_0                           200
#define IDI_1                           201
#define IDI_2                           202
#define IDI_3                           203

and I load them like this

h0 = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDI_0), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
h1 = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDI_1), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
h2 = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDI_2), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
h3 = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDI_3), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);

I also checked the exe file with resourcehacker and found all bitmaps in there.

What I do not understand is that only sometimes (~50%) when I run the game pops either

Error 1812: The specified image file did not contain a resource section. 

or

Error 1813: The specified resource type cannot be found.

But if I load them from files like this

h0 = (HBITMAP)LoadImage(NULL, L"D:\\User\\Mark\\Documents\\C++\\win32\\MineSweeper\\MineSweeper\\empty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
h1 = (HBITMAP)LoadImage(NULL, L"D:\\User\\Mark\\Documents\\C++\\win32\\MineSweeper\\MineSweeper\\1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
h2 = (HBITMAP)LoadImage(NULL, L"D:\\User\\Mark\\Documents\\C++\\win32\\MineSweeper\\MineSweeper\\2.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
h3 = (HBITMAP)LoadImage(NULL, L"D:\\User\\Mark\\Documents\\C++\\win32\\MineSweeper\\MineSweeper\\3.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);

everything works fine.

Any thoughts or advice would be appreciated. Thanks!

  • Maybe your hInst parameter is incorrect, you could log all the parameter and determine whether the resource exists with `FindResource`. – Jichao Aug 06 '15 at 14:39
  • @Jichao Thanks for your reply! I used the starter code generated by vs2013, including window class init and registers. Anything I have to change there? and any ideas why it only goes wrong half of the times? – Yichao Shen Aug 06 '15 at 14:53
  • Just a guess; but would you be willing to change LR_CREATEDDIBSECTION to LR_DEFAULTCOLOR? I'm just not familiar with that value. – A.J. Aug 06 '15 at 15:40
  • @user3282085 Thank you! I just tired it, did not work out tho – Yichao Shen Aug 06 '15 at 15:50
  • Try passing `NULL` in place of `hInst`. Is it working? – Jet Aug 06 '15 at 15:52
  • @Jet I just tried it and that gives me a 100% error 1814, pretty sure NULL works with standalone files instead – Yichao Shen Aug 06 '15 at 15:58
  • Maybe [this](http://stackoverflow.com/questions/31440563/winapi-error-1812) and [this](http://stackoverflow.com/questions/14909101/findresource-gives-error-1813-on-exe-file?rq=1) can help you? Someone there suggested in comments to check if hInstance is valid? – Jet Aug 06 '15 at 16:12
  • 1
    You can try replacing hInst with `GetMoudleHandle(NULL)`. If that doesn't work, try creating a MCVE, you'll probably find your mistake that way: http://stackoverflow.com/help/mcve – Ross Ridge Aug 06 '15 at 16:22
  • @RossRidge GetModuleHandle worked! I am still confused about this. The hInst I was using was taken from WinMain, how is it not the correct one? Thanks again tho, I can accept it if you want to put it in the answer section – Yichao Shen Aug 06 '15 at 16:40
  • @Jet I found out it was still the problem with hInst. Threads you show me are very helpful! Thanks again – Yichao Shen Aug 06 '15 at 16:41
  • 1
    You should figure out why the hInst value isn't correct. You might be overruning a buffer or something. – Ross Ridge Aug 06 '15 at 16:48
  • @RossRidge You are right, I had an out of bound indexing in the stack above this one. I was led by this error message and never checked the other lines. – Yichao Shen Aug 06 '15 at 17:08
  • So, problem is solved ?) – Jet Aug 06 '15 at 17:37

1 Answers1

0

I'd personally consider using GDI+ to load your images. You can still load from a disk-file or from the resources section of your application. It also gives you the advantage of access to all the image formats that windows supports natively (BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF)

To use it, you just have to initialize GDI+ first and then perform a shutdown before program exit.

Here's the function I use for loading from disk-file:

// BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF
HBITMAP mLoadImageFile(wchar_t *filename)
{
    HBITMAP result = NULL;
    Bitmap bitmap(filename, false);
    bitmap.GetHBITMAP(0, &result);
    return result;
}

If we have a resource-file that contains the following:

IDR_PNG1           RT_PNG            ".\\girl.png"
IDR_JPG1           RT_JPG            ".\\rssLogo.jpg"

Then we can load each of the images thusly:

HBITMAP png = loadImgResource(IDR_PNG1, L"RT_PNG");
HBITMAP jpg = loadImgResource(IDR_JPG1, L"RT_JPG");

Also the two functions I use to load from a resource. You'll note that I've hardcoded in GetModuleHandle(0) in the 2nd function - change this if you want to read from any module (dll, exe) other than the current one.

// BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF
HBITMAP loadImgResource(wchar_t *pName, wchar_t *pType, HMODULE hInst)
{
    Gdiplus::Bitmap *m_pBitmap;
    HBITMAP result=NULL;

    HRSRC hResource = FindResource(hInst, pName, pType);
    if (!hResource)
        return NULL;

    DWORD imgSize = SizeofResource(hInst, hResource);
    if (!imgSize)
        return NULL;

    const void *pResourceData = LockResource(LoadResource(hInst, hResource));
    if (!pResourceData)
        return NULL;

    HANDLE m_hBuffer = GlobalAlloc(GMEM_MOVEABLE, imgSize);
    if (m_hBuffer)
    {
        void* pBuffer = GlobalLock(m_hBuffer);
        if (pBuffer)
        {
            CopyMemory(pBuffer, pResourceData, imgSize);
            IStream* pStream = NULL;
            if (CreateStreamOnHGlobal(m_hBuffer, FALSE, &pStream) == S_OK)
            {
                m_pBitmap = Gdiplus::Bitmap::FromStream(pStream);
                pStream->Release();
                if (m_pBitmap)
                {
                    if (m_pBitmap->GetLastStatus() == Gdiplus::Ok)
                    {
                        m_pBitmap->GetHBITMAP(0, &result);
                        delete m_pBitmap;
                    }
                }
            }
            GlobalUnlock(m_hBuffer);
        }
        GlobalFree(m_hBuffer);
    }
    return result;
}

HBITMAP loadImgResource(WORD resNum, LPWSTR pType)
{
    return loadImgResource(MAKEINTRESOURCE(resNum), pType, GetModuleHandle(0));//hInst);
}
enhzflep
  • 12,927
  • 2
  • 32
  • 51
  • Why GDI+, and not, say, the [Windows Imaging Component](https://msdn.microsoft.com/en-us/library/windows/desktop/ee719902.aspx)? – IInspectable Aug 06 '15 at 19:01
  • (a) Because I'm already familiar with it and (b) because code making use of WIC appears to be COM interface heavy. Never a particularly pleasant thing - especially with non-microsoft tooling. What, if any benefits would there be in using WIC instead? Can I still pump out a sub 10kb exe without resorting to exotic linkers like crinkler or exe-packers like UPX? – enhzflep Aug 06 '15 at 19:08
  • Why would WIC add more payload over GDI+? It's not like the on-demand decoders get somehow statically linked into the executable image. As for the COM involved: You need to `CoCreate` a factory, ask for a decoder based on a file stream, and decode the frame(s) you're interested in. This is easily doable, with any toolset. See the [WIC Image Viewer Using Direct2D Sample](https://msdn.microsoft.com/en-us/library/windows/desktop/ee720057.aspx) in case you're interested. Or have a look at some [decoder sample code](https://msdn.microsoft.com/en-us/library/windows/desktop/ee719870.aspx). – IInspectable Aug 06 '15 at 19:27
  • I dont know enough about WIC to know. If one DLL exports fewer functions than the other and all exported functions are used, the static size will be different, no? As for the samples - a copy/pasted sample for WIC from MSs site fails to compile - no `Wincodecsdk.h` file found. On the other hand, the GDI+ stuff works straight out of the box and is trivial to use with MASM. Direct2D is another technology I'm not exactly enamoured with. GDI+ just works and is in the circumstances which I require it, far simpler than anything you've proposed so far. Do you have answers, or just questions? – enhzflep Aug 06 '15 at 19:41
  • Yes, imports add size to an image. Not sure what you're trying to get at here, but late binding (as COM does) won't add any imports. The sample code compiles, out of the box, provided, that the developer knows how to set up their build system. You should have no difficulty with that. I'm not sure, why you assumed that D2D is a requirement. It isn't. It's just what one of the samples uses for display. You don't like it? Don't use it. Since you've asked about the merits of using WIC: Support for a wide range of image formats and pixel formats (lots more than GDI+ supports). – IInspectable Aug 06 '15 at 21:34
  • 1
    Also, for someone who hates COM so much, it's surprising to witness their love for `IStream`s. With that out of the way, you could just use that `IStream` with WIC, and call [CreateDecoderFromStream](https://msdn.microsoft.com/en-us/library/windows/desktop/ee690309.aspx) on it. This is hardly any more effort. Another (potential) advantage: WIC is available for Windows Store apps, while GDI+ is not. – IInspectable Aug 06 '15 at 21:41
  • Thanks for the Windows Store remark - that sounds like an important distinction. I know how to setup my environment, but elect not to download each and every SDK that MS releases and the ported one I'll need for gcc. I never assumed D2D was a requirement - you've got that wrong (I addressed d2d because you mentioned it, nothing else) As for the comment about Image/Pixel formats - that does indeed sound promising. Certainly worthy of investigation in the future. Thanks. :) – enhzflep Aug 06 '15 at 23:39
  • This does not answer the question that was asked. – David Heffernan Aug 07 '15 at 13:20
  • @DavidHeffernan - perhaps you and I disagree about the appropriate response to _"Any thoughts or advice would be appreciated."_ ? If so, it would seem that my answer while accepted, is inappropriate. – enhzflep Aug 07 '15 at 13:22
  • The question was about the 1812/1813 errors caused by asked passing a defectiive module handle. It's a pretty weak question without a reproduction. But you've not addressed that issue at all. Very hard to see why GDI+ would be needed to load bitmap resources. – David Heffernan Aug 07 '15 at 13:24
  • GDI+ isn't needed to load images. You and I both know that. Quite simply, the suggestion was made because it results in smaller overall application size and greater choice when it comes to suitable image formats. _Surely_ you're aware of that already? Given that the original problem has (and at the time of posting, had) been solved already, I saw no benefit in addressing it.You're perfectly entitled to down-vote if you deem the answer not useful. My aim is only to help. All feedback, whether negative or positive, allows me to refine my efforts to do so. – enhzflep Aug 07 '15 at 13:32
  • If application size is the driving factor, then why did you not provide a WIC solution? Surely, you cannot beat the 2 imports from OLE32.DLL for WIC (`CoInitialize[Ex]`/`CoCreateInstance`) with any GDI+ based solution, now can you? – IInspectable Aug 10 '15 at 13:05
  • Buzz off mate. I already told you I'm not very familiar with WIC. Now you've come to a solved question to try to provoke me into playing with you. Unfortunately, I, like Olaf have much better things to do. Now go away and stop creating unnecessary noise in the comments jnr. – enhzflep Aug 11 '15 at 02:54
  • Cute. So even after I introduced you to the wondrous world of COM and late-binding, you still keep babbling about decreased overall application size. **You** were provoking a response. And failed to answer the genuine question: Why don't you use a solution that provides a smaller overall application size if a smaller overall application size is all that important to you? Stop talking about smaller overall application size, or provide a solution that produces overall smaller applications. – IInspectable Aug 11 '15 at 12:33