Detect if mouse button is down - c++

I am new to c++ and I am trying to activate a line of code only when the left mouse button is held down. In this example, my code works but it seems that it just toggles it. When I click, it spams the H key then, when I click again, it stops.
Currently I have this code:
if ((GetKeyState(VK_LBUTTON)))
{
keybd_event(VkKeyScan('H'),0,0,0);
Sleep ( 30 );
}
Edit:
I have inside the function:
int WINAPI WinMain ( HINSTANCE hInst, HINSTANCE P, LPSTR CMD, int nShowCmd );

Use this to determine if the button is pressed.
if((GetKeyState(VK_LBUTTON) & 0x8000) != 0)
http://vcpptips.wordpress.com/tag/vk_lbutton/

The application can catch messages and process being sent to your window indicating a state change of any mouse button.
When the left button is pressed a
WM_LBUTTONDOWN
is sent.
When it is released
WM_LBUTTONUP
is sent.
Please read here for various messages being sent to indicate mouse events.

Use the below to detect left mouse button press
if(GetAsyncKeyState(VK_LBUTTON)){
//your code controls here
}
You can find more controls here : https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate
Also if the GetAsyncKeyState(VK_LBUTTON)shows a syntax error, try including winuser.h by adding #include <winuser.h> in the includes of your code.
Here is an example
if(GetKeyState(VK_LBUTTON))
{ //finding clicked position
HWND hWnd = FindWindowA(0,("Motion Paths"));
::GetWindowThreadProcessId(hWnd,&pid);
if (hWnd) { cout << "Found" << endl;}
POINT p;
GetCursorPos(&p);
if (ScreenToClient(hWnd, &p))
{
int mouseX = p.x;
int mouseY = p.y;
cout<< p.x << " "<< p.y <<endl;
}
}

In first - need DEFINE BUTTON ID(or another object ID) in begin code:
#define ID_BUTTON1 105
Then AFTER creationale of hWnd - we make button:
HWND HwndButton1 = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"OK", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
10, // y position
100, // Button width
100, // Button height
hWnd, // Parent window
(HMENU) ID_BUTTON1, // ID кнопки в меню
NULL, // Сущность мне неведомая 8-)
NULL); // Pointer not needed.
And then add trigger in function:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId=0, wmEvent; //wmId NEED DEFINE null - if he is not available in event, else be ашипка
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmEvent = HIWORD(wParam); // Name of EVENT - имя события
wmId = LOWORD(wParam); // ID element for event - элемент с которым оно случилось
case WM_LBUTTONDOWN: MessageBox(NULL, L"MouseL_Click", L"WndHeader", MB_OK | MB_ICONEXCLAMATION); // Left Mouse Button pressed
if( LOWORD(wParam) == 105 && WM_COMMAND == WM_LBUTTONDOWN){ // Клик по ID_BUTTON1 левым мышком
EndDialog(hWnd,0);
}
................ // Many another function
}

Related

How to handle VK_MENU (alt) keypresses properly using WinAPI?

I am writing a windows application using the WinAPI (win32) on C++, but can't figure out what's happening with the ALT key. I am handling both WM_KEYDOWN and WM_SYSKEYDOWN, so all keypresses should be coming through. However, while every ALT keyup is detected, every second ALT keydown is being skipped.
Do I have to generate my own keydown event whenever I get a second WM_SYSKEYUP in a row, or am I doing something wrong with my message handling?
Details
Tap these keys: ALT ALT ALT ALT ALT (alt five times)
Expected message sequence: DUDUDUDUDU (down then up, repeated five times)
Observed message sequence: DUUDUUDU (every second down is missing)
Tap these keys: ALT C ALT C ALT C ALT C ALT C (add other keypresses in between - release ALT before tapping C)
Expected VK_MENU message sequence: DUDUDUDUDU (down then up, repeated five times)
Observed VK_MENU message sequence: DUDUDUDUDU (as expected!)
It seems that adding other keypresses (or even mouse events) cancels whatever Windows was doing and forces it to send the app all the ALT keypresses.
Example code (Visual c++17):
Creates a window which adds 'D' to the window title when ALT is pressed and 'U' when ALT is released
#ifndef UNICODE
#define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#define STRICT
#include <Windows.h>
#include <optional>
#include <malloc.h>
WCHAR* title;
int titleLen = 0;
const int maxTitleLen = 64;
void updateWindowTitle(WCHAR c, HWND hwnd)
{
if (titleLen >= maxTitleLen) return;
title[titleLen++] = c;
title[titleLen] = 0;
SetWindowTextW(hwnd, title);
}
LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_SYSKEYDOWN: //needed for keys like alt (VK_MENU)
case WM_KEYDOWN:
//process_keydown_event(wParam);
if (!(lParam & 0x40000000)) { //ignore autorepeat
if (wParam == VK_MENU) updateWindowTitle(L'D', hwnd);
}
break;
case WM_SYSKEYUP: //needed for keys like alt (VK_MENU)
case WM_KEYUP:
//process_keyup_event(wParam);
if (wParam == VK_MENU) updateWindowTitle(L'U', hwnd);
break;
//etc...
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// *********** STANDARD BORING SETUP BELOW ************
std::optional<int> processMessages() noexcept
{
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
// Return argument to PostQuitMessage as we are quitting
return msg.wParam;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return {}; //return empty optional when not quitting
}
int CALLBACK WinMain(
HINSTANCE hInst,
HINSTANCE hPrevInst,
LPSTR lpCmdLine,
int nShowCmd)
{
// Make global title point to valid memory
title = static_cast<WCHAR*>(malloc(sizeof(WCHAR) * maxTitleLen));
// Register window class
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.hInstance = hInst;
wc.hIcon = nullptr;
wc.hIconSm = nullptr;
wc.hCursor = nullptr;
wc.hbrBackground = nullptr;
wc.lpszMenuName = nullptr;
wc.lpszClassName = L"my window class name";
RegisterClassEx(&wc);
// Create window 800x500
HWND hwnd = CreateWindowW(
wc.lpszClassName, L"",
WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 500,
nullptr, nullptr, hInst, nullptr
);
// (check HWND is not NULL)
//main loop
while (true)
{
if (const auto errorcode = processMessages())
{
return errorcode.value();
}
}
}
I can reproduce the problem through code, and then I capture the message of the window through spy++.
We can see that when the ALT key is pressed for the first time, the WM_SYSKEYDOWN and WM_SETTEXT messages are successfully triggered:
When the ALT key is pressed the second time, it actually triggers the WM_SYSKEYDOWN message, but after a series of message sending(WM_CAPTURECHANGED,WM_MENUSELECT...).This resulted in the message not being processed in the main window, but sent to hmenu:00000000, so the main window did not process the WM_SYSKEYDOWN message.
You can handle it by processing the WM_SYSCOMMAND message:
case WM_SYSCOMMAND:
if (wParam == SC_KEYMENU)
{
return 0;
}
else
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
It works for me.

Why does my subclassed button procedure mess up my program?

I am relatively new to C++. I have a question why the program posted below behaves the way it does when the constant DEMOMETHOD is set to 1 in main.cpp and button_class.h.
The program demonstrates subclassing a few buttons created by a single c++ class - there are 4 instances of the class (4 buttons) and two (labeled button1 and button2) are subclassed.
I'm hoping to learn:
why return 0; is needed in the handler of the wm_lbuttondown message in button_class.cpp for multiinstance subclassing to work correctly (set DEMOMETHOD = 0 for correct program operation).
why the other subclassed buttons and the non subclassed buttons work incorrectly after either one of the two subclassed buttons are clicked. Example: the quit button doesn't work if you first click on Button 2 (or 1) when DEMOMETHOD = 1.
I posted compilable (gcc compiler, Windows 7) code to make it easier to observe the behavior I saw and to, hopefully, help other new c++ programmers that stumble upon this post.
Thanks in advance.
//best way to use a defined constant in two cpp files is to use a header (.h) file that is shared by the two cpp files.
//I want to minimize how many files I post, so I define DEMOMETHOD in two separate files
//also set to 1 or 0 in button_class.h
#define DEMOMETHOD 1 //SET TO 1 to make program break, set to 0 to make program work (do this in the button_class.h file too)
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#include <tchar.h> //for _T
//windows 7 flags
#define WINVER 0x0601
#define _WIN32_WINNT 0x0601 // Windows 7 https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=vs-2019
#define _WIN32_IE 0x0700 //windows 7
#define WIN32_LEAN_AND_MEAN //results in smaller exe
#include <windows.h>
#include <iostream>
#include "button_class.h"//my button class
using namespace std;
//forward declares
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
std::string str(long data);
//declares-pre
#define IDC_CHECKBOX101 101
#define IDC_BUTTON1 102
#define IDC_BUTTON2 103
#define IDC_STATIC 104
//globals, create 4 buttons using our button class, 2 will be subclassed
Button bt,cbt,bt1,bt2;//button and checkbox button
HWND hDlg,hstatic; //main window and static label
TCHAR szClassName[ ] = _T("MyWindowsApp");
HINSTANCE hInstance;
//main window, starts the program
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpszArgument,int nCmdShow)
{
HWND hwnd;
MSG messages;
std::string tmp;
hInstance = hInst;//save instance to global variable
//create and register our main window class
WNDCLASSEX wincl; // Data structure for the windowclass
wincl.hInstance = hInst;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WndProc; // This function is called by windows
wincl.style = CS_DBLCLKS; // Catch double-clicks
wincl.cbSize = sizeof (WNDCLASSEX);
// Use default icon and mouse-pointer
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; // No menu
wincl.cbClsExtra = 0; // No extra bytes after the window class
wincl.cbWndExtra = 0; // structure or the window instance
wincl.hbrBackground = (HBRUSH) (COLOR_3DFACE+1);
// Register the window class, and if it fails quit the program
if (!RegisterClassEx (&wincl)) {
MessageBox(NULL,"Failed to register WNDCLASSEX.","Error",MB_OK | MB_ICONINFORMATION);
return 1;//exit program on failure
}
//class is registered, now create main window
hwnd = CreateWindowEx (
0,//extended style
szClassName,
_T("Demo Multi Instance of Button Class"),
WS_OVERLAPPEDWINDOW, // styles - default window
CW_USEDEFAULT, // Windows decides the position
CW_USEDEFAULT, // where the window ends up on the screen
777, // The program's width (hardcoded for this demo)
411, // and height in pixels (hardcoded for this demo)
HWND_DESKTOP, // The window is a child-window to desktop
NULL, // No menu
hInst, // Program Instance handler
NULL // No Window Creation data
);
if (!hwnd) {
MessageBox(NULL,"Failed to create main window.","Error",MB_OK | MB_ICONINFORMATION);
return 1;//exit program on failure
}
hDlg = hwnd;//main window
// Make the window visible on the screen
ShowWindow (hwnd, nCmdShow);
UpdateWindow (hwnd);
while (GetMessage (&messages, NULL, 0, 0)) {
// Translate virtual-key messages into character messages
TranslateMessage(&messages);
// Send message to WindowProcedure (WndProc)
DispatchMessage(&messages);
}
// The program return-value is 0 - The value that PostQuitMessage() gave
return messages.wParam;
}
//handle messages intended for main window
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
std::string tmp;
LRESULT checked;
DWORD dwstyles,dwstylesex;
switch (message) { //wndproc handle the messages
case WM_CREATE://create controls
//always on top checkbox button (not subclassed)
dwstyles = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX;
dwstylesex = 0;
cbt.t.hbutton = cbt.Create(hwnd,cbt,dwstylesex,dwstyles,277,8,122,26,(long) IDC_CHECKBOX101,hInstance,"Always on top",false);
//quit button (not subclassed)
dwstyles = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
dwstylesex = 0;
bt.t.hbutton = bt.Create(hwnd,bt,dwstylesex,dwstyles,691,7,65,30,(long) IDCANCEL,hInstance,"&Quit",false);
//button1 (subclassed)
dwstyles = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
dwstylesex = 0;
bt1.t.hbutton = bt1.Create(hwnd,bt1,dwstylesex,dwstyles,50,50,65,30,(long) IDC_BUTTON1,hInstance,"Button1",true);
if (bt1.t.hbutton == NULL) {
MessageBox(NULL,"button1 failed","error",0);
}
//button2 (subclassed)
dwstyles = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
dwstylesex = 0;
bt2.t.hbutton = bt2.Create(hwnd,bt2,dwstylesex,dwstyles,50,90,65,30,(long) IDC_BUTTON2,hInstance,"Button2",true);
if (bt2.t.hbutton == NULL) {
MessageBox(NULL,"button2 failed","error",0);
}
//create a statio control and display information about DEMOMETHOD
hstatic = CreateWindowEx(0,"Static",
#if (DEMOMETHOD == 0)
"Program should work correctly since DEMOMETHOD is set to 0",
#else
"Program should mess up since DEMOMETHOD is set to 1",
#endif
WS_CHILD | WS_VISIBLE,
50, 140,
450, 30,
hwnd,
(HMENU) IDC_STATIC,
hInstance,
NULL);
break;
case WM_SIZE:
break;
case WM_DESTROY: {
PostQuitMessage(0); // send a WM_QUIT to the message queue
break;
}
case WM_CLOSE: {
DestroyWindow(hwnd);
break;
}
case WM_COMMAND: {
switch (LOWORD(wParam)) {// LOWORD ctrlid. The HIWORD specifies the notification code.
case IDC_CHECKBOX101: { // always on top
//leftover functionality from another app
if (HIWORD(wParam) == BN_CLICKED) {
checked = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0);
if (checked) { // Force the program to stay always on top
SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
} else { // else no more topmost program state
SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
}
break;
}
case IDCANCEL: {//quit button
if (HIWORD(wParam) == BN_CLICKED) {
PostMessage(hDlg,WM_CLOSE,0,0);
return 0;
}
break;
}//idcancel
}// loword switch
break;
}//wm_command
default: // for messages that we don't deal with
return DefWindowProc (hwnd, message, wParam, lParam);
} //for switch(msg)
return 0;
}//end wndproc function
std::string str(long data)//convert non decimnal numeric to string
{
try {
return std::to_string((long) data);
} catch(int x) {
return std::to_string((long) data);
}
return "error in str function";
}
button_class.h
#ifndef BUTTONCLASSGUARD
#define BUTTONCLASSGUARD
//best way to use a defined constant in two cpp files is to use a header (.h) file that is shared by the two cpp files.
//I want to minimize how many files I post, so I define DEMOMETHOD in two separate files
//also set to 1/0 in main.cpp
#define DEMOMETHOD 1 //SET TO 1 to make program break (do this in main.cpp file too) set to 0 to make program work
#include <iostream>
//windows 7 flags
#define WINVER 0x0601 //windows 7
#define _WIN32_WINNT 0x0601 // Windows 7 https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=vs-2019
#define _WIN32_IE 0x0700 //windows 7
#define WIN32_LEAN_AND_MEAN //results in smaller exe
#include <windows.h>
//#include <windowsx.h> //for get_x_lparam
#include <commctrl.h> //for subclass safer also make sure linker calls libcomctl32.a (gcc compiler)
class Button //define the Button class
{
private:
public:
struct T { //seems like a more convenient way to allow sets/gets for a class that only I will use
long x;
long xx;
long y;
long yy;
HWND hparent;
HINSTANCE hinstance;
long ctrlid;
HWND hbutton;
} t;
Button() //constructor
{
}
~Button() //destructor
{
}
//forward declares
HWND Create(HWND hparent, Button &tbt,DWORD dwstylesex,DWORD dwstyles, int x,int y, int xx, int yy, long ctrlid, HINSTANCE hinst, std::string Caption, bool SubClassTF);
//next is our callback function for safe subclassing using setwindowsubclass
// https://learn.microsoft.com/en-us/windows/win32/controls/subclassing-overview
//stackoverflow article said static is needed and my testing confirmed this
static LRESULT CALLBACK OnEvent_Button(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
};//Button class end
#endif//buttonclassguard
button_class.cpp
//custom button class
#include "button_class.h"
extern std::string str(long data);//for demo I use extern keyword to give access to str function, normally that function is in a utilities class
HWND Button::Create(HWND hparent, Button &tbt, DWORD dwstylesex, DWORD dwstyles, int x,int y, int xx, int yy, long ctrlid, HINSTANCE hinst, std::string Caption, bool SubClassTF)
{
HWND result;
HGDIOBJ hFont = GetStockObject(ANSI_VAR_FONT);
bool tbool;
static long InstCount = 0;
std::string tmp;
tbt.t.hinstance = hinst;
tbt.t.x = x;
tbt.t.xx = xx;
tbt.t.y = y;
tbt.t.yy = yy;
tbt.t.hparent = hparent;
tbt.t.ctrlid = ctrlid;
//now create a button
tbt.t.hbutton = (HWND) NULL;
if (dwstyles == 0) {
dwstyles = WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS | BS_NOTIFY;
}
if (Caption == "") {
Caption = "&Ok";
}
result = CreateWindowEx(dwstylesex,"Button",
Caption.c_str(),
dwstyles,
tbt.t.x,tbt.t.y,
tbt.t.xx,tbt.t.yy,
hparent,
(HMENU) ctrlid,
hinst,
NULL);
if (!result) {
MessageBox(NULL, "Button creation Failed.", "Error", MB_OK | MB_ICONERROR);
return result;
}
if (hFont > 0) {
SendMessage(result, WM_SETFONT,(WPARAM) hFont, 0);
}
if (SubClassTF == true) {
//subclass if here
InstCount++;//instantiation count
//now subclass using safer method https://devblogs.microsoft.com/oldnewthing/20110506-00/?p=10723 (raymond chen) (safer subclass)
//the 'this' keyword seems to change its stripes depending on whether onevent_button is static or not
// if static it seems to track the instance of the class &tbt)
// if not static (remove static keyword from .h forward declare) it seems to point to the class not an instance of the class
//static is correct for this exercise
tbool = SetWindowSubclass(
result,//window being subclassed
reinterpret_cast<SUBCLASSPROC>(this->OnEvent_Button), //&tbt.OnEvent_Button), //&OnEvent_Button), //or &tbt.onevent_button worked too sort of onevent_button can be outside the class
InstCount, //id of this subclass, my choice
reinterpret_cast<DWORD_PTR>(this) //&tbt)//was: (&tbt) ken suspects use of this is ng since, for mult instances this points to the class not the instance of the class imho semi tested
);//returns bool with result
if (tbool == false) { //subclass failed if false
tmp = "subclass failed for " + Caption;
MessageBox(NULL,tmp.c_str(),"error",0);
}
} //subclass
tbt.t.hbutton = result;
return result;//return hwnd to caller
}//::create funtion end
LRESULT CALLBACK Button::OnEvent_Button(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
//Button *tp = (Button *) dwRefData;//I believe this is the C way, seems to work
Button *tp = reinterpret_cast<Button *>(dwRefData);//c++ way, works
std::string tmp;
switch(uMsg) {
case WM_LBUTTONDOWN: // onevent_button message
tmp = "I got clicked: uidsubclass: " + str(uIdSubclass) + " tp->t.y: " + str(tp->t.y) + " dwrefdata: " + str((long) dwRefData) + " hwnd: " + str((long)hwnd) + " click ypos: " + str((long)HIWORD(lParam));
MessageBox(NULL,tmp.c_str(),"clicked",0);
//question: why is return 0; needed (why do I need to eat the message?)
//if I break; instead, I call defwindowproc and that messes up how the class works if another subclassed button is clicked 2nd
//the nonsubclassed buttons also mess up if DEMOMETHOD is set to 1 and a subclassed button (1 or 2) is clicked before
//a nonsubclassed button. why is that?
#if (DEMOMETHOD == 0)//set demomethod to 1 to break the program
//if here the program/class should work well
MessageBox(NULL,"return 0 next - should work when you click on another button next","message",0);
return 0;//needed else 2nd call by a different subclassed control doesn't work
#else
MessageBox(NULL,"break is next - doesn't work if you click on another button next","message",0);
#endif
break;//calls defwindowproc -> messes up the ability of the class to distinguish between a button1 or button2 click
case WM_DESTROY: {//onevent_button message
//remove the subclass
//raymond says: https://devblogs.microsoft.com/oldnewthing/20031111-00/?p=41883
RemoveWindowSubclass(hwnd,
reinterpret_cast<SUBCLASSPROC>(&tp->OnEvent_Button), //thisfunctionname
reinterpret_cast<UINT_PTR>(uIdSubclass) //uidsubclass
);
break; //or return DefSubclassProc(hwnd,wMsg,lParam,wParam); //per raymond chen
} //wm_destroy
default:
//for regular subclassing: return CallWindowProc(OldButtonWndProc, hwnd, wm, wParam, lParam);
//for safer subclassing do this per: https://learn.microsoft.com/en-us/windows/win32/controls/subclassing-overview
break;//return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
//I'm a c++ beginner. I notice that most samples by experienced c++ programmers just return 0 next, however
//I find that I was using break in the switch(umsg) section and a call to defsubclassproc was needed so I am doing it this way
//note: for regular subclassing we return CallWindowProc(OldButtonWndProc...
return DefSubclassProc(hwnd, uMsg, wParam, lParam);//need this if you plan to use break for any case item
} //onevent_button
In fact, these two problems are caused by the same problem. When you use return 0, you will return directly without calling the DefSubclassProc function outside of switch.
If you use break, you will jump out switch, call the DefSubclassProc function again. This is why the same button is triggered continuously when the DEMOMETHOD value is 1.
So the solution is very simple, you just need to modify the following code:
LRESULT CALLBACK Button::OnEvent_Button(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
//Button *tp = (Button *) dwRefData;//I believe this is the C way, seems to work
Button* tp = reinterpret_cast<Button*>(dwRefData);//c++ way, works
std::string tmp;
switch (uMsg) {
case WM_LBUTTONDOWN: // onevent_button message
tmp = "I got clicked: uidsubclass: " + str(uIdSubclass) + " tp->t.y: " + str(tp->t.y) + " dwrefdata: " + str((long)dwRefData) + " hwnd: " + str((long)hwnd) + " click ypos: " + str((long)HIWORD(lParam));
MessageBox(NULL, tmp.c_str(), "clicked", 0);
//question: why is return 0; needed (why do I need to eat the message?)
//if I break; instead, I call defwindowproc and that messes up how the class works if another subclassed button is clicked 2nd
//the nonsubclassed buttons also mess up if DEMOMETHOD is set to 1 and a subclassed button (1 or 2) is clicked before
//a nonsubclassed button. why is that?
#if (DEMOMETHOD == 0)//set demomethod to 1 to break the program
//if here the program/class should work well
MessageBox(NULL, "return 0 next - should work when you click on another button next", "message", 0);
return 0;//needed else 2nd call by a different subclassed control doesn't work
#else
MessageBox(NULL, "break is next - doesn't work if you click on another button next", "message", 0);
#endif
break;//calls defwindowproc -> messes up the ability of the class to distinguish between a button1 or button2 click
case WM_DESTROY: {//onevent_button message
//remove the subclass
//raymond says: https://devblogs.microsoft.com/oldnewthing/20031111-00/?p=41883
RemoveWindowSubclass(hwnd,
reinterpret_cast<SUBCLASSPROC>(&tp->OnEvent_Button), //thisfunctionname
uIdSubclass //uidsubclass
);
break; //or return DefSubclassProc(hwnd,wMsg,lParam,wParam); //per raymond chen
} //wm_destroy
default:
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
//for regular subclassing: return CallWindowProc(OldButtonWndProc, hwnd, wm, wParam, lParam);
//for safer subclassing do this per: https://learn.microsoft.com/en-us/windows/win32/controls/subclassing-overview
}
//I'm a c++ beginner. I notice that most samples by experienced c++ programmers just return 0 next, however
//I find that I was using break in the switch(umsg) section and a call to defsubclassproc was needed so I am doing it this way
//note: for regular subclassing we return CallWindowProc(OldButtonWndProc...
return 0; //need this if you plan to use break for any case item
} //onevent_button

How can I open and close a popup menu when I click on a window in win32 api?

I made a little window with the win32 api and want to open a popup menu when I click on the window. When I click on it again I want to close the menu if it's still open.
I open the menu on WM_LBUTTONUP, because I want to drag the window on WM_LBUTTONDOWN.
I know when the menu appears or disappears by WM_ENTERMENULOOP and WM_EXITMENULOOP.
I know how to close the menu programmatically, but unfortunately I don't know how to decide whether the menu is open or closed on WM_LBUTTONUP. The problem is that the menu gets automatically closed on WM_LBUTTONDOWN and that's why I can't save the current state of the menu.
It would be great if someone has a hint how to solve this problem.
Additional information:
the whole window is a borderless client-area with a bitmap painted on it
hWnd = CreateWindowExW(WS_EX_TOPMOST, L"MyWindow", 0, WS_POPUP, wndPosX, wndPosY, m_WndWidth, m_WndHeight, 0, 0, m_hInst, 0);
the bitmap gets loaded on WM_CREATE in the WindowProcedure of the window and is painted on WM_PAINT
m_hBitmap = (HBITMAP)LoadImageA(NULL, "MyBitmap.bmp", IMAGE_BITMAP, m_WndWidth, m_WndHeight, LR_LOADFROMFILE);
the window isn't draggable by default, because I don't have a non-client area, that's why I move the window manually on WM_MOUSEMOVE according to the current cursor position
On WM_LBUTTONUP I create the popup menu on top of the window
HMENU hPopupMenu = CreatePopupMenu();
InsertMenuW(hPopupMenu, 0, MF_BYPOSITION | MF_STRING, ID_ITEM_A, L"ItemA");
SetForegroundWindow(hWnd);
RECT wndRect;
GetWindowRect(hWnd, &wndRect);
TrackPopupMenu(hPopupMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, wndRect.left, wndRect.top, 0, hWnd, NULL);
Here is the solution using WindowsHooks for mouse event
You have to catch mouse down event inside the window client area and skip the next mouse up event
in global scope
static HHOOK hMouseHook = 0;
static HWND hMainWindow = 0;
static int nSkipClick = 0;
LRESULT CALLBACK MouseProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
if (wParam == WM_LBUTTONDOWN) {
MOUSEHOOKSTRUCT* p = (MOUSEHOOKSTRUCT*)lParam;
if (WindowFromPoint(p->pt) == hMainWindow) {
POINT pt = p->pt;
ScreenToClient(hMainWindow, &pt);
RECT rct;
GetClientRect(hMainWindow, &rct);
if (PtInRect(&rct, pt))nSkipClick = 1;
}
}
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
in WndProc
case WM_LBUTTONUP:
if (nSkipClick == 0) { // menu not shown before
hMouseHook = SetWindowsHookEx(WH_MOUSE, &MouseProc, NULL, GetCurrentThreadId());
hMainWindow = hWnd;
HMENU hPopupMenu = CreatePopupMenu();
InsertMenuW(hPopupMenu, 0, MF_BYPOSITION | MF_STRING, ID_ITEM_A, L"ItemA");
SetForegroundWindow(hWnd);
RECT wndRect;
GetWindowRect(hWnd, &wndRect);
TrackPopupMenu(hPopupMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, wndRect.left, wndRect.top, 0, hWnd, NULL);
UnhookWindowsHookEx(hMouseHook);
hMouseHook = 0;
}
else {
nSkipClick = 0;
}
break;
I hope this is what you want to do.

Button Control disappears on click - Click Handler does not get fired on Clicking Button - Win32

I am working on Zoom SDK which is based on win32 gui.
I have created 3 buttons using CreateWindow method on the window handle, which is provided by the ZoomSDK.
Code + Screenshot - 1
Now there are two problems with this.
As soon as I click the buttons, they disappear.
See the Screen Shots BEFORE
See the Screen Shots AFTER
I want to know the reason why this is happening and how can I fix this?
HWND hFirstView, hSecondView;
cntrl->GetMeetingUIWnd(hFirstView, hSecondView);
cntrl->MoveFloatVideoWnd(100, 100);
HWND btnHwnd = CreateWindow(
TEXT("button"),
L"Open App",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
0, 0,
50, 25,
hFirstView,
(HMENU)100,
hInst,
NULL);
HWND btnHwnd2 = CreateWindow(
TEXT("button"),
L"Other",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
50, 0,
50, 25,
hFirstView,
(HMENU)101,
hInst,
NULL);
HWND btnHwnd3 = CreateWindow(
TEXT("button"),
L"Raise Hand",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
100, 0,
50, 25,
hFirstView,
(HMENU)103,
hInst,
NULL);
HDC hdc = GetDC(btnHwnd);
SetBkColor(hdc, GetSysColor(COLOR_BTNSHADOW));
SetTextColor(hdc, GetSysColor(COLOR_BACKGROUND));
ReleaseDC(btnHwnd, hdc);
int btnId = GetDlgCtrlID(btnHwnd);
//oldWndProc = (WNDPROC) GetWindowLong(hFirstView, GWL_WNDPROC);
oldWndProc = (WNDPROC) SetWindowLong(hFirstView,
GWL_WNDPROC, (LONG)WndProc);
SendMessage(btnHwnd, BM_SETSTATE, 1, 0);
SetWindowText(hFirstView, L"Title");
I want to handle click event for these buttons. I have tried to use SetWindowsLong to set another WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int id = GetWindowLong(hWnd, GWL_ID);
switch (message)
{
case WM_COMMAND: {
MessageBox(NULL, L"Sign of releaf!", L"Whoaa!", 0);
if (wParam == 1023) {
MessageBox(NULL, L"Sign of releaf!", L"Whoaa!", 0);
}
}
break;
}
return CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
}
Now, this WndProc gets called for other events such mouse move etc. It is not working for my three buttons. I want to handle click event i.e WM_COMMAND or any other technique possible.
Because I can not go inside the sdk (they don't provide sources, only .lib) so I can not change their WndProc, nor their internal WM_PAINT. The buttons are sort of overlay on top.
You should not be calling SetBkColor() and SetTextColor() from outside a WM_PAINT handler. The correct way to color a button is to either:
have the parent window handle the WM_CTLCOLORBTN notification.
The WM_CTLCOLORBTN message is sent to the parent window of a button before drawing the button. The parent window can change the button's text and background colors. 
give the button the BS_OWNERDRAW style, and then have the parent window handle the WM_DRAWITEM notification.
Sent to the parent window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.
Also, when a button sends a BN_CLICKED notification to its parent window, your subclass WndProc() doesn't need to use GetWindowLong(GWL_ID). First, you are calling it on the wrong HWND. And second, the button ID is carried in the message's wParam data.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_COMMAND: {
if (HIWORD(wParam) == BN_CLICKED) {
switch (LOWORD(wParam)) {
case 100:
case 101:
case 103:
MessageBox(NULL, L"Sign of relief!", L"Whoaa!", 0);
break;
}
}
break;
}
}
return CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
}

C++ WinAPI TextOut() update text

I'm creating a Windows application with WinAPI. I'm using the TextOut() function to display updated text to the user when handling the WM_PAINT message for the window.
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, hfDefault);
// display the user data in the window
TextOut(hdc,10,70, "Points: 0", 9);
TextOut(hdc,10,85, "Level: 0", 8);
// ...
EndPaint(hwnd, &ps);
}
break;
How can I change the text printed by TextOut() after the function is called as well as the last parameter that determines the length of the printed text?
Everything I've found about using TextOut() was about the text font.
Maybe something like this....
// I'll assume hwnd is global
void OnSomeActionToRefreshValues()
{
HDC hdc = ::GetDc(hwnd);
DrawValues(hdc, 88, 99);
ReleaseDC(hdc);
}
void DrawValues(HDC hdc, int points, int level)
{
// Might need a rectangle here to overwrite old text
SelectObject(hdc, hfDefault); // I assume hfDefault is global
TCHAR text[256];
swprintf_s(text, 256, L"Points: %d", points);
TextOut(hdc, 10, 70, text, wcslen(text));
swprintf_s(text, 256, L"Level: %d", level);
TextOut(hdc, 10, 85, text, wcslen(text));
}
And in you win proc:
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwnd,&ps);
DrawValues(hdc, 88, 99);
EndPaint(hwnd,&ps);
break;
In order to update the displayed text in a window when handling the WM_PAINT message, you will need to have some source for the text string to be displayed.
Since your original post is somewhat old, the Windows API has changed with new versions of Windows, with the current version of Windows 10 and Windows 11 already in beta.
Windows since Windows XP is 16 bit UNICODE for the WinAPI so people mostly use wchar_t text characters. This requires that text character string constants need the L modifier as in L"wchar_t text".
Using Visual Studio 2019, I put together a simple example that runs with Windows 10. This is a simple Windows WinAPI desktop GUI application. I started with a new project in Visual Studio and had the IDE generate the skeleton for a Windows Desktop GUI application with the wWinMain(), MyRegisterClass(), InitInstance(), and WndProc().
Then I modified that generated source to do the following:
present in the main window four buttons to allow data changes
display two text strings which are updated with counts for button clicks
I elected to use the default font so did not do anything to modify the font used to display the text. If you need to modify the font, you will need to add the code to create the font you want, select the new font into the HDC for drawing the text, then use TextOut() to draw the text with the new font. After using the font you would need to swap it back out and then delete it.
The first step was to create a data area for managing the buttons and button clicks. I chose to create the buttons in the InitInstance().
static struct {
const wchar_t* txt; // pointer to text to display on button face
int iCount; // count of number of times button clicked
HWND hwnd; // button window handle which identifies the button
} myButtons[] = {
{L"Points up", 0, 0},
{L"Points dwn", 0, 0},
{L"Level up", 0, 0},
{L"Level dwn", 0, 0}
};
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
// create the displayed window along with the buttons.
// the buttons are in a single row at the top of the window.
POINT myPoint = { 10, 10 }; // x, y
for (auto &a : myButtons) {
a.hwnd = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
a.txt, // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
myPoint.x, // x position
myPoint.y, // y position
100, // Button width
50, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL); // Pointer not needed.
myPoint.x += 100 + 20; // button width plus a separation distance
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
The source code for updating the displayed window follows. We have two functions, a button click handler to determine which button was clicked and the WndProc() with the WM_PAINT message handler which modifies the displayed window.
// process a button click event and return an indication
// whether the button handle matches one we are managing (1)
// or not managing (0).
int buttonClick(HWND hWnd, HWND hButton)
{
// look through the list of buttons to see if the window handle
// of the button event matches one of our buttons.
for (auto &a : myButtons) {
if (a.hwnd == hButton) {
// this is one of our buttons so we increment button click count.
// then invalidate the window area and update to trigger WM_PAINT message.
a.iCount++;
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
return 1; // indicate we processed this event.
}
}
return 0; // indicate we did not process this event
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
int wmCode = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
// not a menu event so see if it is a button click or not.
if (wmCode == BN_CLICKED) {
// if we are managing this button then we skip
// the DefWindowProc() otherwise it is called.
if (buttonClick(hWnd, (HWND)lParam))
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
// create the text strings we are going to display/update
wchar_t myText[2][64];
// following swprintf_s() works because template
// generates the proper call with the additional buffer
// size argument.
swprintf_s(myText[0], L"Points: %d", myButtons[0].iCount - myButtons[1].iCount);
swprintf_s(myText[1], L"Level: %d", myButtons[2].iCount - myButtons[3].iCount);
// get the text metrics of the font we are using to draw the text so
// that we can find out how tall the letters are and can adjust the
// distance for each line of text properly.
TEXTMETRIC myTextMetric = { 0 };
GetTextMetrics(hdc , &myTextMetric);
// we will use a POINT struct for maintaining the point at which
// the text output will start. x coordinate is horizontal position
// and y coordinate is the vertical position.
POINT myPoint = { 10, 150 }; // x, y
int myMargin = 5;
// iterate over the list of strings we are displaying and
// display each one on a separate line.
for (auto &a : myText) {
TextOut(hdc, myPoint.x, myPoint.y, a, wcslen(a));
myPoint.y += myTextMetric.tmHeight + myMargin;
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}