1

I'm trying to load a png to my button, but it's not showing the png in my button.

I create my button with this function:

HWND MyControls::CreateButton(LPCTSTR text, int x, int y, int w, int h, HMENU id, HWND hwnd, HINSTANCE hInst, bool png){
        if (png){
            return CreateWindow("BUTTON", text, BS_BITMAP | WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
                x, y, w, h, hwnd, id, hInst, NULL);
        }
        else{
            return CreateWindow("BUTTON", text, WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
                x, y, w, h, hwnd, id, hInst, NULL);
        }   
}    

Add PNG to button (WM_CREATE):

void MyControls::AddPngBtn(HWND hwnd, const WCHAR* fileName){
    Bitmap bmp(fileName);
    HBITMAP tBmp;
    bmp.GetHBITMAP(Color(0, 0, 0, 0), &tBmp);
    SendMessage(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)tBmp);
    ShowWindow(hwnd, SW_SHOW);
    DeleteObject(tBmp);
}    

And how I initialize GDI+:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(szCmdLine);
    UNREFERENCED_PARAMETER(iCmdShow);

    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    if (!Wnd.RegClassEx(hInstance)) return 0;
    if (!Wnd.CreateMyWindow(hInstance)) return 0;

    GdiplusShutdown(gdiplusToken);

    return Wnd.MyMsg();
}    

The LPARAM is not NULL;
My button size: 25x25;
My png size: 24x24;
And i don't have a error in the "Error List".

What should I do, or what am I doing wrong?

Júlio
  • 15
  • 6
  • BS_OWNERDRAW is not my solution, i think there is a way to load a png without the BS_OWNERDRAW. The second question the guy don't want to use GDI+. (you just deleted what you have posted) And i'm using the tag c++ because i'm thinking about people that use c++ and gdi+. And i know that Win32 API is C based. Ty for your help and time. – Júlio Dec 27 '14 at 02:56
  • OK, good luck to you. Sorry for the interruption. – jww Dec 27 '14 at 02:58
  • You can interruption when you want. You are a master i'm a noob yet. – Júlio Dec 27 '14 at 02:59
  • 2
    `STM_SETIMAGE` doesn't copy the bitmap you pass in (in general), so you can't delete the bitmap as you are doing until the control is destroyed. – Jonathan Potter Dec 27 '14 at 03:10
  • Have you reviewed this question: [How to create a C++ button with an icon](http://stackoverflow.com/q/13461653/608639) and this answer: [How would I load a PNG image using Win32/GDI (no GDI+ if possible)?](http://stackoverflow.com/a/26897254/608639). It seems like ICO is the way to go unless you are boxed into PNG. Or maybe its possible to convert PNG to ICO on the fly and then use the ICO. I don't use the picture buttons, so I can only help you find related items that may be helpful. – jww Dec 27 '14 at 03:11
  • Ty, i'm going to try it now. – Júlio Dec 27 '14 at 12:32
  • I got it to load my png but it is not transparent. So, I'm using Paint.net program to convert my png's to bmp and now it's transparent. Ty for your help. If i find another solution i will post here. Now i'm looking msdn for something about the image position in a button. – Júlio Dec 27 '14 at 13:18

1 Answers1

2

As Jonathan Potter pointed out in the comments, STM_SETIMAGE needs the HBITMAP to stick around. The clean-up semantics are somewhat convoluted, but you cannot generally call DeleteObject before WM_DESTROY.

Mitch
  • 21,223
  • 6
  • 63
  • 86
  • That's true. But i don't understand why i should only delete the object in WM_DESTROY since i'm calling a PostQuitMessage(0) there. – Júlio Dec 27 '14 at 12:38
  • You should not delete the `HBITMAP` while it is in use. It is in use (typically) until you receive `WM_DESTROY`, so you shouldn't call `DeleteObject` before you receive `WM_DESTROY`. You don't _have_ to call `DeleteObject` at all, but you will end up with a leak which persists until you end the process. – Mitch Dec 27 '14 at 12:58