[Win32] WM_PAINT & LoadImage()?

5ccedf5e0f538b594eb578f003ade3eb
0
Hyper 96 Apr 07, 2012 at 01:37 c++

Hello.

I have a question, and I believe I already know the answer, but I am going to ask anyway, as I am extremely unfamiliar (still) with the Win32 API.
I will try to format this as best as I can, as it’s slightly confusing to reference it…

If you were loading multiple bitmap images (let’s say 50), and needed to render them everytime the screen updated (WM_PAINT notification)…
Should you be calling LoadImage() during every iteration, or should you save the HDC? HBITMAP? And simply BitBlit per image per iteration (WM_PAINT)?

Thank you in advance. :)

7 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Apr 07, 2012 at 02:26

Definitely do LoadImage() once and save the returned HBITMAP.

5ccedf5e0f538b594eb578f003ade3eb
0
Hyper 96 Apr 07, 2012 at 03:23

Perhaps you could show me where I went wrong with that assumption then…?

void IMAGE::repaint() {

    // "hdc" is set to BeginPaint()'s hdc value right before calling
    HDC hdcMem = CreateCompatibleDC(hdc);

    // image is an HBITMAP member stored from "HBITMAP image = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);"
    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, image);

    // This is absolutely valueless... but I used it anyway (I already know the dimensions, considering I created them)
    GetObject(image, sizeof(bm), &bm);

    // GetLastError() says this always returns 0/the function always returns 0
    BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);

    SelectObject(hdcMem, hbmOld);

    // Stop memory leaks (GDI object count loves to sky-rocket)
    DeleteDC(hdcMem);
    DeleteObject(image);

Am I running into yet another magical undocumented wall, that I seem to always find…? Thanks again.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Apr 07, 2012 at 03:29

Well, if you do LoadImage() once then of course you shouldn’t do DeleteObject() on that object until you are shutting down your application. That code looks like it’s deleting it after the first time it’s rendered.

(Also, for efficiency you can also create the memory DC once and save it, rather than creating and deleting it each frame.)

5ccedf5e0f538b594eb578f003ade3eb
0
Hyper 96 Apr 07, 2012 at 03:35

By removing the DeleteDC/Object, it creates a massive memory leak:
ss5fV.jpg

Whether you use the classes individually defined DC or a locally created one on the stack, it doesn’t work.
BitBlt still returns 0, and still fails inevitably without reason or explanation.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Apr 07, 2012 at 03:40

Something else must be going on with your GDI objects, because that makes no sense. LoadImage() creates an object and DeleteObject() deletes it. Just selecting it into a DC doesn’t create an object and you’re selecting it out again at the end of the paint function, which is correct.

Anyway, the rest of the code you posted looks correct to me. You’re not getting anything from GetLastError()?

5ccedf5e0f538b594eb578f003ade3eb
0
Hyper 96 Apr 07, 2012 at 03:52

I agree, it makes absolutely no sense. Granted, I believe I just found where/why it is not working the way you’d expect it to;

In the initial function which loads the image, and sets up the values, this is what I originally had:

...
    HDC hdcMem = CreateCompatibleDC(hdc);
    this->hdcMem = hdcMem;

    HBITMAP image = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    this->image = image;

Apparently, you cannot copy the values straight over like that. I was under the impression (the debugger showed the same values) it was working fine.
In the initial loadImage() function, I believe what I’m going to do now is absolve all locally defined functions, and simply use the class’ innate ones.

In the destructor of the class, I should be (for safety sake, and not relying on the operating system) calling the DeleteObject/DeleteDC, correct?

Thank you again for the help, as always (through-out the years). :)

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Apr 07, 2012 at 03:54

Yeah, if you wrap the GDI objects in classes, it would be appropriate to call DeleteObject/DeleteDC in the destructor.