BM_GETCHECK not working - c++

I have code like this :
In WM_CREATE
hCheckBox = CreateWindowEx(0,"Button","Random text", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS| BS_AUTOCHECKBOX | BS_TEXT | WS_GROUP | WS_TABSTOP,150,323,300,20,hwnd,0,hInstance,0) ;
In WM_COMMAND
if ( SendMessage( hCheckBox , BM_GETCHECK, (WPARAM) NULL, (LPARAM) NULL ) == BST_CHECKED )
MessageBox( 0, "Working", "Msg", 0 );
Doesn't matter if the checkbox is checked or not, it never return BST_CHECKED.
Trying to make it work for the last 2 hours :(

It is not entirely apparent whether hCheckBox is a local automatic variable. If so, I can assure you it is not holding its value from the time the CreateWindow fires until the time the WM_COMMAND message is received. Use this instead:
LRESULT chk = SendDlgItemMessage(hDlg, IDC_CHECKBOX_CTRL_ID, BM_GETCHECK, 0, 0);
Where hDlg is your dialog or main window handle, and IDC_CHECKBOX_CTRL_ID is the control ID. To that, you need to specify the control id as a non-zero value for the HMENU parameter to your create-call:
hCheckBox = CreateWindowEx(0,"Button","Random text", WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS| BS_AUTOCHECKBOX | BS_TEXT | WS_GROUP |
WS_TABSTOP,150,323,300,20,hwnd, IDC_CHECKBOX_CTRL_ID, hInstance,0);
And in case it wasn't obvious. Define IDC_CHECKBOX_CTRL_ID as a non-zero integer.
EDIT
Assuming the control is setup correctly, you should be able to handle the WM_COMMAND for this checkbox as follows in your WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
case WM_CREATE:
CreateWindowExA(0,"Button","Random text", WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS| BS_AUTOCHECKBOX | BS_TEXT | WS_GROUP |
WS_TABSTOP,100,100,300,48, hWnd, (HMENU)IDC_CHECKBOX_CTRL_ID, hInst, 0);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
if (wmId == IDC_CHECKBOX_CTRL_ID)
{
if (wmEvent == BN_CLICKED)
{
LRESULT chkState = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0);
if (chkState == BST_CHECKED)
MessageBoxA(hWnd, "Checkbox is checked!", "CheckBox", MB_OK);
}
break;
};
// fall-thru intentional
default:
return DefWindowProc(hWnd, message, wParam, lParam);
};
return 0;
}
I just slammed this into a stock generic WIN32 app with a blank window. the results are in the image below:

Related

c++ winapi - best practice for switching between 2 different sets of buttons/control layouts in the same window on button press

I'm a hobbyist programmer coming back to C++ after many years away from programming and new to winapi so sorry for the "basic" GUI question. I'm trying to find the best practice for implementing the following, very common, behaviour.
From a users perspective this is the behaviour I want to create. I have 1 window with some buttons in it. The user clicks on 1 of the buttons and the window contents appears to change to show different buttons/text fields etc. The user interacts with these controls then finally clicks a "back" button and they are returned to the first screen.
This behaviour is so common I thought it would be easy to find examples and best practices for implementing it but clearly I'm not asking the right questions in google. Not sure if the right way forward is a new window, a child window and how to set up winproc to capture the events in these 2 options, i.e. a winproc for each window or child or 1 massive winproc for everything. Hence the best practice question.
Can anyone help, either be explaining the best way to set this up with the WINAPI or by pointing me to some material online. I've spent days looking, plenty on creating 1 windows with controls. Very happy to follow tutorials and experiment to learn more.
Thanks jwezorek I got very close to your updated code last night but still couldn't get the child events to work. Finally cracked it using your updated code and putting the page switch buttons in the same pane as the other buttons so all clicks were handled on a pane basis in the child winproc. Thank you all for your help. Code below in case it's of interest/use to anyone else.
#include <windows.h>
#define PANE1_ID 101
#define BUTTON11_ID 102
#define BUTTON12_ID 103
#define BUTTON_TO_PAGE_1 104
#define PANE2_ID 201
#define BUTTON21_ID 202
#define BUTTON22_ID 203
#define BUTTON_TO_PAGE_2 204
LRESULT CALLBACK parentWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK childWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
HINSTANCE g_hinst;
static HWND g_pane1;
static HWND g_pane2;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
g_hinst = hInstance;
MSG msg = { 0 };
// Parent window definition
WNDCLASS parentWindow = { 0 };
parentWindow.lpfnWndProc = parentWndProc;
parentWindow.hInstance = hInstance;
parentWindow.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
parentWindow.lpszClassName = L"MainWindow";
if (!RegisterClass(&parentWindow))
return 1;
// Child window definition
WNDCLASS childWindow = { 0 };
childWindow.lpfnWndProc = childWndProc;
childWindow.hInstance = hInstance;
childWindow.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
childWindow.lpszClassName = L"Pane";
if (!RegisterClass(&childWindow))
return 1;
// Create main window
if (!CreateWindow(parentWindow.lpszClassName, L"grouped buttons", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, NULL))
return 2;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK parentWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
// create pane 2 with button then hide the pane and the button to switch to pane 1
g_pane2 = CreateWindow(L"Pane", L"", WS_CHILD | WS_VISIBLE, 20, 20, 250, 200, hWnd, (HMENU)PANE2_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Button 2.1", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 50, 10, 180, 35, g_pane2, (HMENU)BUTTON21_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Button 2.2", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 50, 40, 180, 35, g_pane2, (HMENU)BUTTON22_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Back to Page 1", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 50, 130, 180, 35, g_pane2, (HMENU)BUTTON_TO_PAGE_1, g_hinst, 0);
ShowWindow(g_pane2, SW_HIDE);
UpdateWindow(g_pane2);
// create pane 1 with buttons and show it and the button to switch to pane 2
g_pane1 = CreateWindow(L"Pane", L"", WS_CHILD | WS_VISIBLE, 20, 20, 250, 200, hWnd, (HMENU)PANE1_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Button 1.1", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 10, 10, 180, 35, g_pane1, (HMENU)BUTTON11_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Button 1.2", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 10, 40, 180, 35, g_pane1, (HMENU)BUTTON12_ID, g_hinst, 0);
CreateWindow(L"BUTTON", L"Go to page 2", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 10, 130, 180, 35, g_pane1, (HMENU)BUTTON_TO_PAGE_2, g_hinst, 0);
ShowWindow(g_pane1, SW_SHOW);
UpdateWindow(g_pane1);
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK childWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_COMMAND) {
switch (wParam) {
case BUTTON_TO_PAGE_2:
{
// MessageBox(hWnd, L"You pressed go to page 2", L"Button Pressed", MB_OK);
ShowWindow(g_pane1, SW_HIDE);
ShowWindow(g_pane2, SW_SHOW);
}
break;
case BUTTON11_ID:
MessageBox(NULL, L"Button 1.1", L"Page 1 Button", 0);
break;
case BUTTON12_ID:
MessageBox(NULL, L"Button 1.2", L"Page 1 Button", 0);
break;
case BUTTON_TO_PAGE_1:
{
// MessageBox(hWnd, L"You pressed go to page 1", L"Button Pressed", MB_OK);
ShowWindow(g_pane2, SW_HIDE);
ShowWindow(g_pane1, SW_SHOW);
}
break;
case BUTTON21_ID:
MessageBox(NULL, L"Button 2.1", L"Page 2 Button", 0);
break;
case BUTTON22_ID:
MessageBox(NULL, L"Button 2.2", L"Page 2 Button", 0);
break;
}
return 0;
}
else {
return DefWindowProc(hWnd, message, wParam, lParam);
}
}

WM_COMMAND unabled to fulfil request unless clicked outside of application window,

Currently creating an application that just outputs Physics equations + some historical and mathematical context. I've ran into this problem where I'm using WS_EX_CLIENTEDGE to sort out a list of these terms and when I click said term on the screen, expecting a definition to appear, it doesn't output anything until I've clicked outside of the application window(Visual Studio, Debug Terminal, etc)
Cursed gif
And I want to make it clear that I DON'T want to use a button due to GUI aesthetics.
Mundane WINAPI application creation
int main(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
const wchar_t CLASS_NAME[] = L"Application";
WNDCLASS window = { 0 };
MSG msg = { 0 };
window.lpfnWndProc = WindowProc;
window.lpszClassName = CLASS_NAME;
window.hInstance = hInstance;
RegisterClass(&window);
HWND hWnd = CreateWindow(CLASS_NAME, L"PhysicsBox", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100, 600, 500, NULL, NULL, NULL, NULL);
ShowWindow(hWnd, nCmdShow);
//aMessageBox = CreateWindowW(L"edit", L" ", WS_VISIBLE | WS_CHILD | WS_BORDER, 165, 150, 400, 300, hWnd, NULL, NULL, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
The Juicy Window Procedure
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
aListBox(hWnd);
break;
case WM_COMMAND:
if (SendMessage(hList, LB_GETSEL, FORCE, 0))
{
CreateWindowW(L"static", L"Simple Text", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 100, hWnd, NULL, NULL, NULL);
}
break;
case WM_DESTROY:
PostQuitMessage(0); break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
The void function that creates the list
void aListBox(HWND hWnd)
{
hList = CreateWindowEx(WS_EX_CLIENTEDGE, L"ListBox", L" ", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_AUTOVSCROLL, 3, 4, 150, 300, hWnd, (HMENU)ID_LISTBOX, 0, 0);
SendMessageW(hList, LB_ADDSTRING, FORCE, (LPARAM)L"Force");
SendMessageW(hList, LB_ADDSTRING, WORK, (LPARAM)L"Work");
SendMessageW(hList, LB_ADDSTRING, POWER, (LPARAM)L"Power");
SendMessageW(hList, LB_ADDSTRING, EFFICENCY, (LPARAM)L"Efficency");
SendMessageW(hList, LB_ADDSTRING, POTENTIALENERGY, (LPARAM)L"Potential Energy");
SendMessageW(hList, LB_ADDSTRING, HOOKESLAW, (LPARAM)L"Hooke's Law");
}
Note: the MSG('s) placed in the "aListBox(HWND hWnd)" SendMessageW parameters are numerically ordered(from 0). So FORCE = 0, WORK = 1, and so on. Also hList is a global variable if that helps :P
The listbox is created without the LBS_NOTIFY style and will therefore not send LBN_SELCHANGE notifications to the parent window. Changing the first line in aListBox to the following fixes this.
hList = CreateWindowEx(WS_EX_CLIENTEDGE, L"ListBox", L" ", WS_CHILD | LBS_NOTIFY | WS_VISIBLE | WS_VSCROLL | ES_AUTOVSCROLL, 3, 4, 150, 300, hWnd, (HMENU)ID_LISTBOX, 0, 0);
Also, the WindowProc does not return a result on all code paths, and does not call DefWindowProc for all messages that it does not handle. The following corrects those issues.
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
aListBox(hWnd);
return 0;
case WM_COMMAND:
if (SendMessage(hList, LB_GETSEL, FORCE, 0))
{
HWND hText = CreateWindowW(L"static", L"Simple Text", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 100, hWnd, NULL, NULL, NULL);
ShowWindow(hText, SW_SHOW);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Other problems remain with the code, for example the WindowProc does not check the WM_COMMAND notification code and will happily create new windows over and over, but the assumption was that this was minimal code only meant to showcase the particular issue in the question.
[ EDIT ]   The behavior described by the OP when running without the LBS_NOTIFY style bit is mostly accidental, due to WM_COMMAND not checking the WPARAM notification code. What happens is that clicking outside the app window causes the listbox to send a LBN_KILLFOCUS notification (which is being sent regardless of LBS_NOTIFY). That notification is the one which triggers the WM_COMMAND code in WindowProc that creates the static control when the FORCE item is selected.

How to add functionality of Enter/Return key in an Edit Control

I know that in Win32 API (no MFC), in an edit control, there's no functionality of enter key. In a standard textbox, when we press the enter key, the cursor jumps to the next line. I want to add that function of the enter key to the edit control.
I tried subclassing and I was able to detect enter key press but how do I jump to the next line?
This is the following subclass :-
LRESULT CALLBACK EditProc
(
HWND hWnd,
UINT msg,
WPARAM wp,
LPARAM lp,
UINT_PTR uIdSubclass,
DWORD_PTR dwRefData
)
{
switch (msg)
{
case WM_CHAR :
{
if (wp == VK_RETURN)
{
// Add functionality here
}
break;
}
default :
{
return DefSubclassProc (hWnd, msg, wp, lp);
}
}
return 0;
}
You can refer to How to Create a Multiline Edit Control:
I create a sample with the following code:
#define ID_EDITCHILD 100
LRESULT CALLBACK WndProc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static HWND hwndEdit;
RECT rect;
switch (message)
{
case WM_CREATE:
GetClientRect(hwnd, &rect);
hwndEdit = CreateWindowEx(
0, L"EDIT",
NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOVSCROLL,
0, 0, 200, 200,
hwnd,
(HMENU)ID_EDITCHILD,
NULL,
NULL);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return NULL;
}
And it works for me:
Yeah finally, I found the answer. I would like to implement what #CodyGray and #ZhuSong-MSFT said and here's the code :-
HWND hTb = CreateWindow
(
L"Edit", L"LOL",
WS_VISIBLE | WS_CHILD | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_HSCROLL | WS_VSCROLL | ES_WANTRETURN,
0, 0, LOWORD (lp), HIWORD (lp),
hWnd, NULL, NULL, NULL
);
This even includes adding a horizontal and a vertical scrollbar.
If anyone wants to dock the textbox in the fill area, I have a solution :-
case WM_SIZE :
{
MoveWindow (hTb, 0, 0, LOWORD (lp), HIWORD (lp), TRUE);
break;
}
Just put the above code in the WndProc function of the main window.

Edit control doesn't work correctly

I started to learning winapi c++ today. And i wrote this simple program that have to change window name to the name that i write in text box:
#include <Windows.h>
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
void AddMenu(HWND);
void AddControl(HWND);
HWND hEdit;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrewInst, LPSTR args, int ncmdshow)
{
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"class";
wc.lpfnWndProc = WindowProcedure;
if (!RegisterClassW(&wc))
return -1;
CreateWindowW(L"class", L"Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, NULL, NULL);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_COMMAND:
switch (wp)
{
case 1:
MessageBeep(MB_SERVICE_NOTIFICATION); break;
case 2:
DestroyWindow(hWnd); break;
case 3:
wchar_t text[100];
GetWindowTextW(hEdit, text, 100);
SetWindowTextW(hWnd, text);
break;
}
case WM_CREATE:
AddMenu(hWnd);
AddControl(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
}
void AddMenu(HWND hWnd)
{
HMENU hMenu;
hMenu = CreateMenu();
HMENU file;
file = CreateMenu();
HMENU Sub;
Sub = CreateMenu();
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)file, "File");
AppendMenu(file, MF_STRING, 1, "Open");
AppendMenu(file, MF_POPUP, (UINT_PTR)Sub, "Sub");
AppendMenu(file, MF_STRING, 2, "Exit");
AppendMenu(Sub, MF_STRING, 3, "Change");
SetMenu(hWnd, hMenu);
}
void AddControl(HWND hWnd)
{
CreateWindowW(L"Static", L"Enter text: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 20, hWnd, NULL, NULL, NULL);
hEdit = CreateWindowW(L"Edit", L"...", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL, 200, 152, 100, 50, hWnd, NULL, NULL, NULL);
}
By default in text box i have .... So i run my program, starting to type hello world for expample but nothing changes. I highlited my 3 dots that had to change and boom, my text appeared. I go to the menu choose File -> Sub -> Change and my window name changes to 3 dots ....
BUT! If i delete these: | ES_MULTILINE | ES_AUTOVSCROLL then text box working correctly but menu doesnt show up in my window.
I found that i have to do smth with EN_CHANGE but idk what. I tried to change WM_COMMAND to EN_CHANGE and my textbox worked correctly, but other menu buttons didnt work at all...
Your failure is caused by handling all the edit control notifications the same way. You need to test the notification code (found in HIWORD(wParam)) to see whether it is EN_CHANGE, and let notifications you aren't handling pass through to DefWindowProc.
You also have an even bigger bug in that you reach the closing brace of a function with a non-void return type. You need to always return something; when you aren't calling DefWindowProc the system still expects a return value. The reason things start working when you change WM_COMMAND to EN_CHANGE is not because you are handling EN_CHANGE, it is because you no longer have incorrect handling of WM_COMMAND, and instead let the DefWindowProc take them.
The fall-through from WM_COMMAND into WM_CREATE isn't helping things either.
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (HIWORD(wParam)) /* command kind */
{
case 0: // menus
switch (LOWORD(wParam)) /* child ID */
{
case 1:
MessageBeep(MB_SERVICE_NOTIFICATION);
return 0;
case 2:
DestroyWindow(hWnd);
return 0;
case 3:
wchar_t text[100];
GetWindowTextW(hEdit, text, 100);
SetWindowTextW(hWnd, text);
return 0;
}
break;
}
break;
case WM_CREATE:
AddMenu(hWnd);
AddControl(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
// break actions also reach here
return DefWindowProcW(hWnd, msg, wParam, lParam);
}

Handling button click in button procedure

I'm using the following code to create a button and change it's proc:
INT_PTR CALLBACK Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
//switch( LOWORD(wParam) )
//switch( HIWORD(wParam) )
switch (message)
{
case 200:
case BN_CLICKED:
MessageBox(NULL,NULL,NULL,NULL);
break;
default: return oldproc(hDlg, message, wParam, lParam);
}
return (INT_PTR)FALSE;
}
and
HWND handle = CreateWindowEx( NULL,
L"button",
L"TEXT",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
50,
50,
500,
500,
hWnd,
(HMENU)200,
hInstance,
nullptr);
oldproc = (WNDPROC)SetWindowLong(handle, GWL_WNDPROC, (LONG)Proc);
The problem is that no matter how I handle messages in Proc no messagebox is being created.
Note: commenting last line and handling it in the window proc like so:
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case 200:
if(wmEvent == BN_CLICKED)
MessageBox(NULL,NULL,NULL,NULL);
... }
works fine but I can't use this due to how I designed things.
Is there a way to get this working?
You don't see your message box because BM_CLICK is not a message that the button receives. It is a message you send to the button when you want it to simulate a click action.
What you are looking for is the BN_CLICKED notification instead. However, BN_CLICKED is wrapped inside of a WM_COMMAND message that is sent to the button's parent window, not to the button itself. So you need to subclass the parent window in order to receive it.
If that is not an option, then you can use a thread-specific message hook via SetWindowsHookEx() instead and have that callback look for messages being sent to the button's parent window. For example:
HWND hBtn, hBtnParent;
HHOOK hHook;
LRESULT CALLBACK BtnMsgProc(int iCode, WPARAM wParam, LPARAM lParam)
{
if ((iCode == HC_ACTION) && (wParam == PM_REMOVE))
{
MSG *msg = reinterpret_cast<MSG*>(lParam);
if ((msg->hwnd == hBtnParent) &&
(msg->message == WM_COMMAND) &&
(HIWORD(msg->wParam) == BN_CLICKED) &&
(reinterpret_cast<HWND>(msg->lParam) == hBtn))
{
// button has been clicked...
}
}
return CallNextHookEx(hHook, iCode, wParam, lParam);
}
.
hBtnParent = hWnd;
hBtn = CreateWindowEx(
NULL,
L"button",
L"TEXT",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
50,
50,
500,
500,
hWnd,
(HMENU)200,
hInstance,
NULL);
hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)BtnMsgProc, NULL, GetCurrentThreadId());
...
UnhookWindowsHookEx(hHook);
DestroyWindow(hBtn);
For your question about an example for SetWindowsHookEx: MSDN