Skip to main content
GameDev.net gamedev.net
🔒 Locked

Win32 cant detect button press

Started by DividedByZero May 24, 2010 at 3:02 AM 3 replies 1.3k views
Original Post
DividedByZero
DividedByZero
Hi Guys, I am playing with Parent windows and child windows. All is working as I want except I cant detect the press of IDC_MAIN_BUTTON in the child window.
#include<windows.h>
#include"resource.h"

#define IDC_MAIN_EDIT		WM_USER+1
#define IDC_MAIN_BUTTON		WM_USER+2
#define IDC_MAIN_BUTTON2	WM_USER+3

// function prototypes
void InitApp();
LRESULT CALLBACK MainProc(HWND,UINT,WPARAM,LPARAM);
LRESULT CALLBACK OtherProc(HWND,UINT,WPARAM,LPARAM);

// Global variables
HWND hWnd;
HWND other;
HMENU hMenu=NULL;

// Program entry point
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR line,int CmdShow)
{
	hMenu = LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1));
	
	InitApp();

	MSG msg;
	while(GetMessage(&msg,0,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

// initlize application
void InitApp()
{
	WNDCLASS wc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
	wc.hInstance = GetModuleHandle(NULL); //hInst;
	wc.hCursor = LoadCursor(NULL,IDC_ARROW);
	wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
	wc.lpfnWndProc = (WNDPROC) MainProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL; //(LPCSTR)hMenu;
	wc.style = CS_HREDRAW | CS_VREDRAW;

	RegisterClass(&wc);

	wc.lpszClassName = "Other";
	wc.lpfnWndProc = (WNDPROC) OtherProc;
	wc.hbrBackground = (HBRUSH)16;

	RegisterClass(&wc);

	hWnd = CreateWindow("Main","Accounting Application",WS_OVERLAPPEDWINDOW,0,0,170,55,0,hMenu,GetModuleHandle(NULL),0);
	other = CreateWindow("Other","Customer",WS_OVERLAPPEDWINDOW,200,200,640,480,0,0,GetModuleHandle(NULL),0);

	ShowWindow(hWnd,SW_SHOWMAXIMIZED);
	UpdateWindow(hWnd);
}

// Main CallBack Function
LRESULT CALLBACK MainProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	switch(msg)
	{
		case WM_DESTROY:
		{
			PostQuitMessage(0);
		}
		break;
		case WM_CREATE:
		{
		}
		break;
		case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
				case ID_FILE_EXIT:
				{
					PostQuitMessage(0);
				} 
				break;
				case ID_MASTERFILES_CUSTOMER:
				{
					ShowWindow(other,SW_SHOW);
				} 
				break;	
			}
		}
		break;
		
		default: return DefWindowProc(hWnd,msg,wParam,lParam);
	}
	return 0;
}

// Other Window CallBack Function
LRESULT CALLBACK OtherProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	switch(msg)
	{
		case WM_CREATE:
		{
			HGDIOBJ hfDefault=GetStockObject(DEFAULT_GUI_FONT);
			HWND hButton=CreateWindowEx(NULL,"BUTTON","OK",WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,390,400,100,24,hWnd,(HMENU)IDC_MAIN_BUTTON,GetModuleHandle(NULL),NULL);
			SendMessage(hButton,WM_SETFONT,(WPARAM)hfDefault,MAKELPARAM(FALSE,0));
		}
		break;
		case WM_CLOSE:
		{
			ShowWindow(hWnd,SW_HIDE);
		}
		break;
		case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
				case IDC_MAIN_BUTTON:
				{
					MessageBox(NULL,"Button pressed","Information",MB_ICONINFORMATION);
				}
				break;
			}
			break;
		}
		break;

		default: return DefWindowProc(hWnd,msg,wParam,lParam);
	}
	return 0;
}
This is driving me crazy as I can prove that WM_CREATE and WM_CLOSE work ok in the child window but just cant detect IDC_MAIN_BUTTON. If anyone could help, this would be awesome! Thanks in advance. :)
Endurion
Endurion
What an awesome bug! Took me a while to figure out :)

Note: That's one of the main reasons #define constants are bad. Your IDC_MAIN_BUTTON is

#define IDC_MAIN_BUTTON WM_APP + 2

When inserted in the CreateWindowEx line you cast to HMENU:

(HMENU)IDC_MAIN_BUTTON

Now #defines are inserted literally, this makes it:

(HMENU)WM_APP + 2


Lovely. WM_APP is cast to HMENU (which itself is a strawman typedef for a pointer to a HMENU__ struct). Now pointer arithmetic kicks in and increases the pointer by two instances of the pointee, namely 8 bytes. That's why in your code wParam contains 0x0408 instead of the 0x0402 you expected.

Fix:

Either change the define to have paranthesis:

#define IDC_MAIN_BUTTON (WM_APP + 2)

Or #define a direct value.
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
DividedByZero
DividedByZero
Classic! You just beat me to it.

I tried changing the defines to a constant number and the application started working. I had no idea, in effect, what the difference was though.

Your explanation is awesome! How long did you spend working that out?

You have definately gone above and beyond! If I could rate you up 10 times I would. 1 will have to do though, unfortunately.
Endurion
Endurion
Was a few steps to get there:

First step I did was to stepped into the debugger at the WM_COMMAND handler of the customer dialog. You saw that there was indeed a button press message. It had the wrong ID however (0x0408).

At that points I can only recommend the Spy++ tool from MS; should be installed with Visual Studio. It lets you look at all existing windows and their properties (and beyond that).

From there on just a little bit of checking where the wrong ID came in.

T'was good practise, your code looked correct and yet... ;)


A hint maybe: The customer dialog, is it meant to be completely unrelated to the main window? (both show up in the task bar). You could set the customer dialog's parent to the main window to mark it as owner.
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
DividedByZero
DividedByZero
Mamoth effort you have put in. Well done!

And thanks again.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.