-
Okay, here's the code, but the application doesn't recognize the button click. I'll try some debugging. Right now, MyClickHandler isn't being called correctly. Oh, and "if ( iFunction != mCallback.end() )" is skipping the next line.
Code:
#include <windows.h>
#include <iostream>
#include <string>
#include <map>
typedef LRESULT (MessageCallbackPtr)(WPARAM, LPARAM);
std::map<int, MessageCallbackPtr*> mCallback;
const char g_szClassName[] = "myWindowClass";
LRESULT MyClickHandler(WPARAM wParam, LPARAM lParam)
{
MessageBox(NULL, "Got it", "Click!", MB_OK);
return 0;
}
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
{
std::map<int, MessageCallbackPtr *>::iterator iFunction;
iFunction = mCallback.find(msg);
if ( iFunction != mCallback.end() )
return iFunction->second(wParam, lParam);
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd, hWndButton;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc)) {
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName,
"Win32 Practice",WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL) {
return 0;
}
hWndButton = CreateWindowEx(NULL, "button", "Click Me",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 50, 50, 100, 24, hwnd,
(HMENU)(100), hInstance, NULL);
if (hWndButton == NULL)
return false;
mCallback[WM_LBUTTONDOWN] = &MyClickHandler;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return (int) Msg.wParam;
}
-
Well, I don't know (remember) what message is sent.
So take a look at your window proc when a button is pressed and note the message. The message is what you need to use in the callback map.
-
Whatever it is, it's 273! Thanks! You're brilliant even when you're away from Win32 these days haha...
Edit: I looked into 273, it ended up being 0x111, otherwise, WM_COMMAND. So, I gotta do this...
mCallback[WM_COMMAND] = &MyClickHandler;
WM_COMMAND isn't really clear as of what I'm specifying. But still, it works, but it would be nice to be more specific if possible. It only accepts left button clicks, though, so I guess this is a good thing :) Anyway, thanks for the help tonight.
-
Here's a better suggestion:
Code:
#include <windows.h>
#include <iostream>
#include <string>
#include <map>
typedef LRESULT (MessageCallbackPtr)(WPARAM, LPARAM);
std::map<int, MessageCallbackPtr*> mCallback;
const char g_szClassName[] = "myWindowClass";
LRESULT MyClickHandler(WPARAM wParam, LPARAM lParam)
{
MessageBox(NULL, "Got it", "Click!", MB_OK);
return 0;
}
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
{
std::map<int, MessageCallbackPtr *>::iterator iFunction;
iFunction = mCallback.find( LOWORD(wParam) );
if ( iFunction != mCallback.end() )
return iFunction->second(wParam, lParam);
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd, hWndButton;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc)) {
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName,
"Win32 Practice",WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL) {
return 0;
}
hWndButton = CreateWindowEx(NULL, "button", "Click Me",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 50, 50, 100, 24, hwnd,
(HMENU)(100), hInstance, NULL);
if (hWndButton == NULL)
return false;
mCallback[/* Control ID here, as is sent by the low word of the wParam */] = &MyClickHandler;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return (int) Msg.wParam;
}
If you use the control identifier instead, it should only react for that control. Or you could use the window handle instead. But I don't know if the control's handle is sent via the hwnd argument in the window proc when a control notifies its window.
I'm not used to Pure Win32 programming nowadays. I typically use MFC.
Just add a button to the dialog, give it an ID and double-click it to create an event handler. Handy, isn't it? That's why I remember so little about this mess.
-
Definitely. I use Win32 for game programming and .Net for the job :) I'm trying to build a slim win32 GUI classes for my library, and MFC is just 100x more powerful than I need for games. .Net 3.5 has 200mb of runtime crap too :) Win32 is managable. But yeah... if I was building a game editor I'd consider MFC or C++/CLI.
Oh yeah, the best part of my code:
Code:
void OnClick(MessageCallbackPtr clickEvent)
{
mCallback[WM_COMMAND] = &clickEvent;
}
-
Well, as you know, WM_COMMAND isn't the best message to use for it.
It's better to use the button's specific ID so it won't call the handler for whatever menu or button you click!