I am working on window creation with Win32 API and I'm having a problem with this part:
GetMessage(&message, NULL, 0, 0);
My problem is that when I try to change the second parameter (hwnd) which is going to receive the messages to the window I previously made, it doesn't work; for example, when I try to close the window, it only hides and doesn't close.
Here is the full code:
#include <windows.h>
LRESULT CALLBACK WinProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASS window;
window.cbClsExtra = NULL;
window.cbWndExtra = NULL;
window.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
window.hCursor = LoadCursor(hInst, IDC_ARROW);
window.hIcon = NULL;
window.hInstance = hInst;
window.lpfnWndProc = WinProc;
window.lpszClassName = "WINDOW";
window.lpszMenuName = NULL;
window.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&window);
HWND hwnd = CreateWindow("WINDOW", "Win32 Window Application", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, hInst, NULL);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
return 1;
}
LRESULT CALLBACK WinProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
{
PostQuitMessage(0);
break;
}
default:
break;
}
return DefWindowProc(window, message, wParam, lParam);
}
"... when I try to change the second parameter (hwnd) which is going to receive the messages to the window I previously made, it doesn't work."
Thread messages are not sent to a window; they're posted to the thread message queue with a NULL window handle, and will NOT be picked up with a GetMessage() loop tailored to a specific window handle.
Ex: PostQuitMessage() posts a thread message; not a window message. You need the NULL. From the GetMessage() docs:
If hWnd is NULL, GetMessage retrieves messages for any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL (see the MSG structure). Therefore if hWnd is NULL, both window messages and thread messages are processed.
Related
I have an SDL2 program that opens an SDL window. In the main I create a hook for mouse events as
hMSHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, NULL);
while outside of the main I have the custom mouse event handler
HHOOK hMSHook;
int xPosAbsolute = 0;
int yPosAbsolute = 0;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
auto &ms = *(const MOUSEHOOKSTRUCT *)lParam;
if (wParam == WM_MOUSEMOVE)
{
xPosAbsolute = ms.pt.x;
yPosAbsolute = ms.pt.y;
}
}
return CallNextHookEx(hMSHook, nCode, wParam, lParam);
}
When the window is in focus, the mouse coordinates xPosAbsolute and yPosAbsolute are properly updated as the mouse moves. However, if another window receives focus, these variables stop being updated.
My question is, how do I make SetWindowsHookEx() continue receiving WH_MOUSE_LL events while my window is not in focus?
EDIT:
Actually, as it turns out, SetWindowsHookEx only stopped receiving event updates when the window focus was lost to another window that was launched as administrator, while the SDL2 window of this program was launched as a regular user. Once the current program is launched as administrator as well, all updates continue to come in (using the above code), even when window focus is lost. So this turned out to be a non-issue.
Focus is not required but keep pumping messages is required.
The following is a mini Win32 window application with low level hook you can refer to. It will receive WM_MOUSEMOVE message in all existing threads running in the same desktop as the calling thread regardless of which window holds the focus.
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
auto& ms = *(const MOUSEHOOKSTRUCT*)lParam;
if (wParam == WM_MOUSEMOVE)
{
OutputDebugString(L"\n WM_MOUSEMOVE \n");
OutputDebugStringA(to_string(counter++).c_str());
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
HHOOK hMSHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, NULL);
WNDCLASSEXW wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWindowClass;
RegisterClassExW(&wcex);
HWND hWnd = CreateWindowW(szWindowClass, L"test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
I don't have much experience with windows programming, but can't specifically see what's wrong with this code, yet the window doesn't open. Although sometimes, not always, it will be open in task manager, so my guess is that it is registering the class and creating the window, but the problem is with the ShowWindow() function. But, I'm not positive.
To my understanding the flow of the program is:
Window is created with the registered class.
The window is shown.
Continuously looks for messages that are processed in the window Proc.
I feel like I've done all these things, so is my understanding wrong, or is my code missing something?
Thanks.
Source Code:
#include <Windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}
DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
//Variable for message loop.
MSG msg;
//Setting up the window class.
WNDCLASSEX windowClass;
windowClass.cbSize = sizeof(windowClass);
windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_PARENTDC;
windowClass.lpfnWndProc = WindowProc;
windowClass.hInstance = hinstance;
windowClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
windowClass.lpszClassName = "WindowClass";
RegisterClassEx(&windowClass);
HWND windowHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "WindowClass", "My Program", WS_OVERLAPPEDWINDOW, 500, 200, 800, 500, NULL, NULL, hinstance, 0);
if (!windowHandle)
return FALSE;
ShowWindow(windowHandle, nCmdShow);
// Start the message loop.
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Return the exit code to the system.
return msg.wParam;
}
Your window procedure is invoking DefWindowProc but not actually returning the result, and you have undefined behavior because of that. The return value is important, and it can control how the OS handles successive messages to your window. For example, it's important to return the correct value in response to the WM_CREATE message.
Change your window procedure to:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Also, as Mark Ransom identified in the comments section, you should zero-initialize your WNDCLASSEX structure to ensure that you don't get garbage on any members that you didn't explicitly initialize.
I'm trying to create two instances of a window class.
When the primary one is closed it should close the application but when the secondary one is closed it should just close that window.
However when either window is closed the application exits, and I'm not sure why. I've tried comparing the hWnd to check which window is being closed.
// include the basic windows header file
#include <windows.h>
#include <windowsx.h>
//Forgive me now
#define MAX_WINDOWS 1024
HWND hWindows[MAX_WINDOWS];
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";
RegisterClassEx(&wc);
hWindows[0] = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
500, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
hWindows[1] = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
500, // width of the window
400, // height of the window
hWindows[0], // primary window
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
ShowWindow(hWindows[0], nCmdShow);
ShowWindow(hWindows[1], nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
}
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch (message)
{
case WM_CLOSE:
{
if (hWnd = hWindows[0]) {
// close the application entirely
PostQuitMessage(0);
}
else {
DestroyWindow(hWnd);
}
return 0;
} break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);
}
if (hWnd = hWindows[0])
That's assignment. Since hWindows[0] is non-zero, that expression always evaluates true.
You mean:
if (hWnd == hWindows[0])
You should call PostQuitMessage in response to WM_DESTROY. And since the default window procedure calls DestroyWindow in response to WM_CLOSE, you can write it like this:
switch (message)
{
case WM_DESTROY:
{
if (hWnd == hWindows[0]) {
// close the application entirely
PostQuitMessage(0);
}
return 0;
}
break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);
I have a crazy issue. I subclassed buttons, richedits, checkboxes,.. and all seems working fine. But after I subclassed a trackbar I’m having some trouble now. The problem is that my subclassed messagehandler don’t receive the WM_VSCROLL / WM_HSCROLL messages. They are still sent to the parent's messagehandler. WM_PAINT message and some others are successfully sent to the subclassed messagehanlder.
Someone knows what I’m doing wrong? …And maybe knows how to solve this problem? I created a clean project with the following needed code:
#include <windows.h>
#include <CommCtrl.h>
#pragma comment(lib,"comctl32.lib")
//Prototyps
HWND CreateMainWindow(HINSTANCE hInstance);
LRESULT CALLBACK MessageHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LRESULT CALLBACK SubMessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
WNDPROC oldWndProc;
HWND hWnd = 0;
HWND hTrackBar = 0;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
WNDCLASSEXA wndClass = {sizeof(WNDCLASSEX), CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW, MessageHandler, 0,0, hInstance, LoadIcon(NULL, IDI_WINLOGO),
LoadCursor(NULL, IDC_ARROW),(HBRUSH)GetStockObject(WHITE_BRUSH), NULL, "WindowClass", LoadIcon(NULL, IDI_WINLOGO)};
RegisterClassExA(&wndClass);
//Creat MainWindow
hWnd = CreateWindowExA(NULL, "WindowClass", "Test Windows", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
100, 100, 400, 300, NULL, NULL, hInstance, NULL);
//Creat Trackbar
INITCOMMONCONTROLSEX initCtrlEx;
initCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
initCtrlEx.dwICC = ICC_BAR_CLASSES;
if (InitCommonControlsEx(&initCtrlEx)){
hTrackBar = CreateWindowExA(NULL,TRACKBAR_CLASSA, "TrackBar_Test", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | TBS_AUTOTICKS |
TBS_ENABLESELRANGE | TBS_VERT | TBS_BOTH, 10, 10, 50, 200, hWnd, NULL, hInstance, NULL);
oldWndProc = (WNDPROC)SetWindowLongPtrA(hTrackBar, GWLP_WNDPROC, (LONG_PTR)SubMessageHandler); //Subclassing messagehandler
}
//Message loop
MSG msg;
while (GetMessageA(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
return 0;
}
LRESULT CALLBACK SubMessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_VSCROLL: //callback is subclassed but WM_VSCROLL is not send. why?
MessageBoxA(hWnd, "WM_VSCROLL sent (to SubMessageHandler)", "Test", MB_OK);
break;
}
if (oldWndProc != 0)
return CallWindowProcA(oldWndProc, hwnd, msg, wParam, lParam);
else
return DefWindowProcA(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK MessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_VSCROLL: //Why the hell is the Trackbar WM_VSCROLL still sent here to the parent callback!?!?
MessageBoxA(hWnd, "WM_VSCROLL sent (to Parent)", "Test", MB_OK);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
}
return DefWindowProcA(hwnd, msg, wParam, lParam);
}
From the MSDN documentation on Trackbar controls:
A trackbar notifies its parent window of user actions by sending the
parent a WM_HSCROLL or WM_VSCROLL message.
The Trackbar's contract is to notify the parent window with WM_HSCROLL/WM_VSCROLL. The Trackbar control generates and sends those messages; it does not receive them.
Also note that the Default Trackbar Message Processing section does not list WM_HSCROLL/WM_VSCROLL (but does list WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP, WM_KEYDOWN, WM_KEYUP, which are the raw messages it would need to handle to handle interaction).
As for what to do about it, it probably depends on exactly what you want to do. You could try subclassing and intercepting all of the user input messages, but that seems like a lot of work and is potentially brittle. My recommendation would be to have the parent window explicitly reflect WM_HSCROLL/WM_VSCROLL back to your custom Trackbar control.
Whenever I try to make a c++ gui program/window the command prompt window appears with the window like this:
but all I did was this::
#include <iostream>
#include "define.h"
LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd){
window win;
MSG msg;
win.cbClsExtra = NULL; //Additional parameters
win.cbWndExtra = NULL; //Additional parameters
win.hbrBackground = (HBRUSH)COLOR_WINDOW ; //Sets background color for the window
win.hCursor = LoadCursor(NULL, IDC_ARROW); //The cursor that will appear in the window
win.hIcon = NULL; //Icon for the window
win.hInstance = hInst; //Handle to the application instance
win.lpszClassName = "Window Class"; //The unique name of the window class
win.lpszMenuName = NULL; //Used for menus
win.style = NULL; //The look and feel of the window
win.lpfnWndProc=(WNDPROC)WinProc; //The callback procedure (more on that later)
RegisterClass(&win);
HWND hwnd = CreateWindow("Window Class", "Title", WS_OVERLAPPEDWINDOW, 200, 200, 640, 480, NULL, NULL, hInst, NULL);
ShowWindow(hwnd, SW_SHOWNORMAL);
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){
switch (message){
case WM_CREATE:{
HWND button = CreateWindow("BUTTON", "ok", WS_VISIBLE | WS_CHILD | WS_BORDER, 20, 20, 50, 30, hWnd, NULL, NULL, &lParam);
break;
}
case WM_DESTROY:{
PostQuitMessage(0);
return 0;
break;
}
default:{
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
}
I followed the code just on internet and don't think I did something wrong I want to remove this annoying cmd window by any way...
tysm for all repliers much appreciated...........
EDIT
and btw the define.h is a header file I made and define WNDCLASS as window