HWND hWndButton = CreateWindow(
"BUTTON", // predefined class
NULL, // button text
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON |BS_BITMAP, // styles
//EDIT: ADDED BS_BITMAP
// Size and position values are given explicitly, because
// the CW_USEDEFAULT constant gives zero values for buttons.
10, // starting x position
10, // starting y position
31, // button width
31, // button height
(HWND) hWnd, // parent window
NULL, // No menu
(HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // pointer not needed
HBITMAP oldBMP = (HBITMAP)SendMessage(
// returns LRESULT in lResult
(HWND) hWndButton, // handle to destination control
(UINT) BM_SETIMAGE, // message ID
(WPARAM) IMAGE_BITMAP, // = (WPARAM) () wParam;
(LPARAM) (HBITMAP) bm_right_arrow // = (LPARAM) () lParam;
);
if (!oldBMP)
{
MessageBox (hWnd, "lResult = NULL", "NULL", MB_OK);
}
Using BM_SETIMAGE (button control send message)
I'm trying to use sendmessage to set a button to a bitmap. The bitmap loads properly (I can display it elsewhere in WM_CREATE) but the LRESULT returned from SendMessage is always null and the bitmap is never displayed on the button. Whats wrong with this code?
Any ideas?
[Edited by - d1sc0rd on January 18, 2005 7:16:24 PM]
Your right, I was definitly missing that. Thank you.
It still doesn't work. I tried sending a different message in the same way. Tried sending BM_GETSTATE. It returns a null value as well. Still no bitmap displayed.
It still doesn't work. I tried sending a different message in the same way. Tried sending BM_GETSTATE. It returns a null value as well. Still no bitmap displayed.
The LRESULT should be null, because it returns the handle to the prev bitmap [if any], and since you have just created the button, it shouldn't have a bitmap set yet.
One possible reason the bmp isn't getting displayed is if it doesn't have the right lifetime, and is getting destroyed somewhere. For example if you use the MFC
CBitmap class and do this
SetBmpButton() //this is just pseudo-code, don't woory about syntax
{
CBitmap temp;
Temp.Load(IDB_BITMAP);
Button.SetBitmap(Temp);
}//since temp is local to this function, it gets destroyed here
//causeing the button to display nothing
One possible reason the bmp isn't getting displayed is if it doesn't have the right lifetime, and is getting destroyed somewhere. For example if you use the MFC
CBitmap class and do this
SetBmpButton() //this is just pseudo-code, don't woory about syntax
{
CBitmap temp;
Temp.Load(IDB_BITMAP);
Button.SetBitmap(Temp);
}//since temp is local to this function, it gets destroyed here
//causeing the button to display nothing
Couple of things.
I declared the bitmap locally. I did load the bitmap in WM_CREATE but I declared the bitmap at the top of the file (only file at this point). I also tried BitBlting the bitmap right after the call, and it works just fine.
I tried checking the return from the BM_GETSTATE as well. It should be returning 0 I think, which would be different from null, right?
Also I was wondering, I know that many GDI objects come with default settings that need to be sent back in, such as pens. I was under the impression that the BS_BITMAP setting would cause the Button to have an default object that would need to be returned in order to be destroyed. Would this not register as somehting other than null? I really don't know.
I declared the bitmap locally. I did load the bitmap in WM_CREATE but I declared the bitmap at the top of the file (only file at this point). I also tried BitBlting the bitmap right after the call, and it works just fine.
I tried checking the return from the BM_GETSTATE as well. It should be returning 0 I think, which would be different from null, right?
Also I was wondering, I know that many GDI objects come with default settings that need to be sent back in, such as pens. I was under the impression that the BS_BITMAP setting would cause the Button to have an default object that would need to be returned in order to be destroyed. Would this not register as somehting other than null? I really don't know.
I think you need to post more code since obviously the error doesn't lie in what you've shown us already. Also, If you're able to blit it to the window, why not just go ahead and make the button ownerdraw instead?
If you loaded the bitmap locally, does that mean the HBITMAP is a local variable to your WndProc()? If so, is it declared static? If not then it wont keep its value between calls to WndProc().
I added a second message to load the bitmap twice. The null check no longer shows up, so the send message is working somewhat anyway.
#define WIN_CLASS_NAME "UIClass"#define WIN_APP_NAME "U101"#define WIN32_LEAN_AND_MEAN#include <windows.h>#include ".\resource.h"static HBITMAP bm_right_arrow;HINSTANCE hInst;HWND hWnd;LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);// The main window message handlerLRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){ switch(msg) { case WM_CREATE: { bm_right_arrow = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_RIGHT_ARROW)); if (!bm_right_arrow) { MessageBox(NULL, "Didn't Load", "ERROR", MB_OK); } HWND hWndButton = CreateWindow( "BUTTON", // predefined class NULL, // button text WS_VISIBLE | WS_CHILD | BS_BITMAP | BS_PUSHBUTTON, // styles // Size and position values are given explicitly, because // the CW_USEDEFAULT constant gives zero values for buttons. 10, // starting x position 10, // starting y position 30, // button width 30, // button height (HWND) hWnd, // parent window NULL, // No menu (HINSTANCE) hInst, NULL); // pointer not needed HBITMAP oldBMP = (HBITMAP)SendMessage( // returns LRESULT in lResult (HWND) hWndButton, // handle to destination control (UINT) BM_SETIMAGE, // message ID (WPARAM) IMAGE_BITMAP, // = (WPARAM) () wParam; (LPARAM) bm_right_arrow // = (LPARAM) () lParam; ); oldBMP = (HBITMAP)SendMessage( // returns LRESULT in lResult (HWND) hWndButton, // handle to destination control (UINT) BM_SETIMAGE, // message ID (WPARAM) IMAGE_BITMAP, // = (WPARAM) () wParam; (LPARAM) bm_right_arrow // = (LPARAM) () lParam; ); if (!oldBMP) { MessageBox (hWnd, "lResult = NULL", "NULL", MB_OK); } break; } case WM_DESTROY: PostQuitMessage(wParam); break; case WM_PAINT: { HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd, &ps); HDC hDCMem = CreateCompatibleDC(hDC); HBITMAP oldBM = (HBITMAP) SelectObject(hDCMem, (HBITMAP) bm_right_arrow); BitBlt(hDC, 80, 80, 80, 80, hDCMem, 0, 0, SRCPAINT); // What to do, oh, what to do... EndPaint(hWnd, &ps); break; } case WM_COMMAND: { switch (LOWORD (wParam)) { } } } return DefWindowProc(hWnd, msg, wParam, lParam);}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ hInst = hInstance; WNDCLASSEX wcx; MSG msg; int cxScr = GetSystemMetrics(SM_CXSCREEN); int cyScr = GetSystemMetrics(SM_CYSCREEN); // Define elements of the window class, register wcx.cbSize = sizeof(WNDCLASSEX); wcx.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wcx.lpfnWndProc = WndProc; wcx.cbClsExtra = 0; wcx.cbWndExtra = 0; wcx.hInstance = hInstance; wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcx.hCursor = LoadCursor(NULL, IDC_ARROW); wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wcx.lpszMenuName = MAKEINTRESOURCE(IDMAINMENU); wcx.lpszClassName = WIN_CLASS_NAME; wcx.hIconSm = NULL; if(!RegisterClassEx(&wcx)) return 0; // Create the window: centered, and half the height and width of the screen if(!(hWnd = CreateWindowEx(NULL, WIN_CLASS_NAME, WIN_APP_NAME, WS_OVERLAPPEDWINDOW | WS_VISIBLE, (int)(cxScr / 4), (int)(cyScr / 4), (int)(cxScr / 2), (int)(cyScr / 2), NULL, NULL, hInstance, NULL))) return 0; // Main loop here while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}
It looks to me like your problem is scope. You create hWndButton inside of the WM_CREATE case, so as soon as the windows procedure exits, your handle to the button is destroyed.
I believe that windows (such as buttons) get detroyed automatically, without you having to call a release function.
I'd say try making your button global, or static inside the WndProc.
kingnosis
I believe that windows (such as buttons) get detroyed automatically, without you having to call a release function.
I'd say try making your button global, or static inside the WndProc.
kingnosis
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement