Using BM_SETIMAGE (button control send message)

Started by
16 comments, last by joeremes 19 years, 2 months ago
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?
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);
	}


Any ideas? [Edited by - d1sc0rd on January 18, 2005 7:16:24 PM]
Advertisement
Create the button with the BS_BITMAP style.
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.
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
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 can't believe this is giving me such a hard time :)
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

This topic is closed to new replies.

Advertisement