Windows Messages Bizarreness - c++

Probably just a gross oversight of some sort, but I'm not receiving any WM_SIZE messages in the message loop. However, I do receive them in the WndProc. I thought the windows loop gave messages out to WndProc?
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
case WM_SIZE:
return 0;
break;
}
printf("wndproc - %i\n", message);
// Handle any messages the switch statement didn't
return DefWindowProc (hWnd, message, wParam, lParam);
}
... and now the message loop...
while(TRUE)
{
// Check to see if any messages are waiting in the queue
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
// check to see if it's time to quit
if(msg.message == WM_QUIT)
{
break;
}
if(msg.message == WM_SIZING)
{
printf("loop - resizing...\n");
}
}
else
{
//do other stuff
}
}

If a message is sent by the system to your window while it's in DefWindowProc or elsewhere in that netherworld that's the Windows message queue, then that message is not going to be seen by your message loop at all.
Note that this is only true for sent messages. Posted messages will show up in the message loop.
If you want to filter all messages, use SetWindowsHookEx with your thread ID, and the appropriate hook type. Or better yet, process them properly in your WndProc.

While you've got hold of the sizing gripper, I believe that Windows is running its own message loop. That will dispatch to your message queue, but your loop is out of the picture while the sizing is ongoing.
The frame window will call SetCapture to capture all subsequent mouse messages. Then it'll resize your window as the mouse moves. It'll also pump the message loop; you can see some similar code here: ftp://ftp.ringdale.com/support/Nlynx/Tech%20Support%20Docs/Midrange/EmeraldSeries/ADK/DDE/C/APITERM/TRACK.C. Note the message loop in the middle of that function.
It pumps the queue itself so that the sizing code doesn't have to return until after the resize tracking is complete.
Edit: I bring up the tracking rectangle code since that's how window resizing used to work, showing just a thin rectangular outline of the window, until we got dynamic window resizing where the entire window updates on the fly while you resize. The behavior internally is likely similar.
Edit 2: Still, credit to the guys who mentioned posted vs sent messages... sent messages won't ever go through the message pump. Sent messages quickly boil down to a function call of your wnd proc. Unless they're sent to windows owned by a different thread, which becomes a lot more complex; they get added to an internal queue belonging to the destination thread's message queue, and are processed internally - before posted messages are returned -inside GetMessage. Getting the sent message's return value back to the source thread involves more gyrations :)

WM_SIZING and WM_SIZE are not the same message. I think ordinary mouse operations to resize a window send WM_SIZING first, but if some program sends a WM_SIZE message then you're only going to get WM_SIZE without WM_SIZING.

Related

Determine which window the message was sent (SetWindowsHookEx & WH_KEYBOARD)

I need to be able to determine which window the message is intended for, but I don’t understand how to do it correctly. In WH_MOUSE has a special structure (MOUSEHOOKSTRUCT) that stores the hwnd of the window, but where to get the hwnd in WH_KEYBOARD?
LRESULT CALLBACK messageHandler(int nCode, WPARAM wParam, LPARAM lParam)
{
// ???
}
DWORD WINAPI messageDispatcher(LPVOID thread)
{
hookHandle = SetWindowsHookEx(WH_KEYBOARD, messageHandler, GetModuleHandle(nullptr), *reinterpret_cast<DWORD*>(thread));
if (!hookHandle)
{
return GetLastError();
}
MSG message{};
while (GetMessage(&message, 0, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
return 0;
}
In theory, I could use GetForegroundWindow, but it seems to me that this is a terrible option, because the window can receive a keyboard message from some other process (if another process sends a SendMessage to this window) and not the fact that the current window will be exactly the one for which the message was intended.
At the time a keyboard action is generated, the OS doesn't know yet which window will eventually receive the message. That is why the WH_KEYBOARD hook doesn't provide a target HWND, like a WH_MOUSE hook does (since a mouse message carries window-related coordinates).
When a keyboard message is being routed to a target, the message gets delivered to the window that currently has input focus.
Per About Keyboard Input:
The system posts keyboard messages to the message queue of the foreground thread that created the window with the keyboard focus. The keyboard focus is a temporary property of a window. The system shares the keyboard among all windows on the display by shifting the keyboard focus, at the user's direction, from one window to another. The window that has the keyboard focus receives (from the message queue of the thread that created it) all keyboard messages until the focus changes to a different window.
Since your hook runs inside of the message queue of the target thread, you can use GetFocus() to get the target HWND at that time:
Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue.
Otherwise, you can use a WH_CALLWNDPROC/RET hook instead, which gets called when the message is actually delivered to a window. However, you can't block messages with this hook (as you were asking about in your previous question).
I think what you might be looking for is a hook of type WH_JOURNALRECORD.
With this, the callback procedure that Windows will call in response to the various events that this hook intercepts is of type JournalRecordProc, and the lparam parameter passed to this function points to an EVENTMSG structure, which looks like this:
typedef struct tagEVENTMSG {
UINT message;
UINT paramL;
UINT paramH;
DWORD time;
HWND hwnd;
} EVENTMSG;
And there is your hwnd!

Winapi - Alternatives to WM_CLOSE

I know with Windows notification message, WM_CLOSE refers to closing the window via "X" button on the top right hand corner of the window.
Does anyone know the notification message for closing with File->Exit?
The reason I asked is because I'm trying to implement JNI native code to gracefully close window when user initiated system shutdown. refer to my earlier post (Winapi - SetWindowLongPtr in ShutdownBlockReasonCreate / Destroy implementation of JNI native code) for background.
When clicking on 'X' to close, confirmation dialog box comes up which prevents shutdown reason message from disappearing (when I expect it to disappear after a while). I know File->Exit from menu bar doesn't ask for confirmation, but how do I implement this using windows notification message?
After some digging around the only suggestions I found is to use DestroyWindow. So I tried closing the window using DestroyWindow() function, but it only "Destroys" the window, rather than ending the whole application. Here's my switch statement in my WndProc CallBack function:
switch (message) {
case WM_QUERYENDSESSION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case WM_ENDSESSION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
break;
}
Any help would be much appreciated!
Cheers
I know with Windows notification message, WM_CLOSE refers to closing the window via "X" button on the top right hand corner of the window.
Actually, when the window's standard "X" button is clicked (or the standard "Close" item on the window's top-left corner menu is selected if enabled, or the window receives an ALT+F4 keystroke), a WM_SYSCOMMAND message is issued to the window with the wParam containing the SC_CLOSE flag. If that message is passed to DefWindowProc() (the default behavior), it then issues a WM_CLOSE message to the window.
See Closing the Window.
It is possible that other conditions can also cause a WM_CLOSE message to be issued.
Does anyone know the notification message for closing with File->Exit?
What happens when that menu item is selected is defined by the application, not the OS. The application can do whatever it wants, including destroying the window immediately if it wants to.
However, that being said, if the menu is a standard Win32 menu, then the window will receive a WM_COMMAND message containing the ID of the menu item that was selected, at least.
The reason I asked is because I'm trying to implement JNI native code to gracefully close window when user initiated system shutdown.
By default, you don't need to do anything for that. The OS automatically closes all open windows during system shutdown. Rather than closing your window manually, you should instead react to your window being closed, if you need to clean up any resources.
When clicking on 'X' to close, confirmation dialog box comes up which prevents shutdown reason message from disappearing (when I expect it to disappear after a while).
Then the application is not handling system shutdown correctly.
Most applications present such a confirmation box in response to receiving the WM_CLOSE message. If the confirmation is aborted, the application discards the message and moves on. However, applications shouldn't prompt the user for confirmation during system shutdown. But not all applications follow that rule.
I know File->Exit from menu bar doesn't ask for confirmation
Again, that is for the application to decide, not the OS.
how do I implement this using windows notification message? After some digging around the only suggestions I found is to use DestroyWindow.
Correct. Or, you can alternatively post a WM_QUIT message to the message queue instead. See the PostQuitMessage() function.
So I tried closing the window using DestroyWindow() function, but it only "Destroys" the window, rather than ending the whole application.
It is the application's responsibility to terminate itself, usually by exiting its message loop when its main window has been destroyed.
Here's my switch statement in my WndProc CallBack function:
There is no need to post WM_CLOSE in response to WM_QUERYENDSESSION or WM_ENDSESSION. Let the OS handle that for you.
If you don't want the confirmation to appear during system shutdown, change your code to something more like this:
bool shuttingDown = false;
LRESULT CALLBACK AppWndProc(
_In_ HWND hWnd,
_In_ UINT message,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ UINT_PTR uIdSubclass,
_In_ DWORD_PTR dwRefData
) {
switch (message) {
case WM_QUERYENDSESSION:
shuttingDown = true;
break;
case WM_ENDSESSION:
if (wParam == FALSE)
shuttingDown = false;
break;
case WM_CLOSE:
if (shuttingDown) {
DestroyWindow(hWnd);
// or:
// PostQuitMessage(0);
return 0;
}
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
break;
}
return DefSubclassProc(hWnd, message, wParam, lParam);
}
There's no specific message to handle your File>Exit. You must handle it as any other menu item:
Define an identifier for your menu item. Choose anything you want, it has no particular meaning for windows.
When constructing your menu, specifiy this identifier in AppendMenu/InsertMenu/etc. or in your resource file
In your window procedure, intercept the WM_COMMAND message. If LOWORD(wParam) corresponds to the identifier, this means that the menu item has been activated
A typical way of handling an exit command is to send a WM_CLOSE message, as you are already doing in your example code.
So you will avoid code duplication and be sure that the behavior will be the same regardless of how the user choose to exit your application (via menu, click on the "x", or Alt+F4)
In the handing of WM_CLOSE, you can choose to show a message box, destroy the window, post a quit message, or whatever else you want. BY default the DefWindowProc calls DestroyWindow, which in turn sends the WM_DESTROY message.
Note that WM_CLOSE is also triggered when selecting the "Close" item of the system menu (Alt+Space or click on the window icon on the left next to the window title)

Why can't I get a WM_DESTROY or WM_CLOSE message outside a window procedure?

I wanted to read out messages in my message loop right before I dispatch them to my window procedure. Most messages I tried reading like this were read correctly, but when I close the window, a WM_CLOSE or WM_DESTROY message could not be read as it seems as if they were never received. Here's what i do:
void Framework::Run(){
while(running){
MSG msg;
while(PeakMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
switch(msg.message){
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_QUIT:
running = false;
break;
//...other cases...
}
DispatchMessage(&msg);
}
//...
}
}
I put a breakpoint at the first case, but even when I close the window (by clicking the 'X') the breakpoint is never hit. Though, when I check for WM_DESTROY in the window procedure, it gets read and every thing goes fine. Why not outside it?
Are such messages sent directly to the window proc? How?
A message loop only sees messages that are posted to the calling thread's message queue. Not all messages go through the message queue. WM_DESTROY is one such message. What you should be doing instead is handling the messages in the window procedure so you see every message that the window receives, whether the message went through the message queue or not.
If you need to look at messages for a window you are not creating yourself, or for a standard window that has a system-provided window procedure, you can subclass the window using SetWindowLongPtr(GWLP_WNDPROC) or SetWindowSubclass(). See Subclassing Controls for more details.

If MessageBox()/related are synchronous, why doesn't my message loop freeze?

Why is it that if I call a seemingly synchronous Windows function like MessageBox() inside of my message loop, the loop itself doesn't freeze as if I called Sleep() (or a similar function) instead? To illustrate my point, take the following skeletal WndProc:
int counter = 0;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
SetTimer(hwnd, 1, 1000, NULL); //start a 1 second timer
break;
case WM_PAINT:
// paint/display counter variable onto window
break;
case WM_TIMER: //occurs every second
counter++;
InvalidateRect(hwnd, NULL, TRUE); //force window to repaint itself
break;
case WM_LBUTTONDOWN: //someone clicks the window
MessageBox(hwnd, "", "", 0);
MessageBeep(MB_OK); //play a sound after MessageBox returns
break;
//default ....
}
return 0;
}
In the above example, the program's main function is to run a timer and display the counter's value every second. However, if the user clicks on our window, the program displays a message box and then beeps after the box is closed.
Here's where it gets interesting: we can tell MessageBox() is a synchronous function because MessageBeep() doesn't execute until the message box is closed. However, the timer keeps running, and the window is repainted every second even while the message box is displayed. So while MessageBox() is apparently a blocking function call, other messages (WM_TIMER/WM_PAINT) can still be processed. That's fine, except if I substitute MessageBox for another blocking call like Sleep()
case WM_LBUTTONDOWN:
Sleep(10000); //wait 10 seconds
MessageBeep(MB_OK);
break;
This blocks my application entirely, and no message processing occurs for the 10 seconds (WM_TIMER/WM_PAINT aren't processed, the counter doesn't update, program 'freezes', etc). So why is it that MessageBox() allows message processing to continue while Sleep() doesn't? Given that my application is single-threaded, what is it that MessageBox() does to allow this functionality? Does the system 'replicate' my application thread, so that way it can finish the WM_LBUTTONDOWN code once MessageBox() is done, while still allowing the original thread to process other messages in the interim? (that was my uneducated guess)
Thanks in advance
The MessageBox() and similar Windows API functions are not blocking the execution, like an IO operation or mutexing would do. The MessageBox() function creates a dialog box usually with an OK button - so you'd expect automatic handling of the window messages related to the message box. This is implemented with its own message loop: no new thread is created, but your application remains responsive, because selected messages (like for painting) are handled calling recursively your WndProc() function, while other messages are not transmitted, because of the modal type of the created window.
Sleep() and other functions (when called directly from your WndProc() handling a window message) would actually block the execution of your single threaded message loop - no other message would be processed.
MessageBox runs its own Win32 message loop (so as not to freeze calling app).
Beware of using it in non reentrant functions...
EDIT: to elaborate:
Message loop on windows is something like that (stolen from msdn):
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DispatchMessage will call whatever window procedure it needs to. That window proc can start its own loop (on the same thread), and it will call DispatchMessage itself, which will call whatever message handlers.
If you want to see it, launch your app in debugger, pop up message box and break. You will be dropped somewhere within its loop. Look at the callstack and see if you can find parent loop.

Windows message loop

Theres some reason for this code not reach the first else?
I got it exactly the same from vairous sources. Than I did my own encapsulation. Everything goes fine. Window is created, messages are treated, events are generated to keyborad input in the client area, the gl canvas works fine (when I force it to draw).
The only problem is that message loop never leaves the first if. :/
I'm really stuck.
while (!done)
{
if (::PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
done = TRUE;
}
else
{
::TranslateMessage (&msg);
::DispatchMessage (&msg);
}
}
else
{
// Code is never reaching this!
draw ();
::SwapBuffers(hDC);
idle ();
}
}
return msg.wParam;
In your case the message queue must never be empty - why? Well it depends on what the rest of your program is doing. Some possibilities:
Your code is posting new messages to the queue in a manner such that the queue doesn't get empty. I'd suggest logging out the message ids as they are handled.
You aren't handling paint messages - from msdn:
"The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a NULL update region, PeekMessage does remove it from the queue."
Hope this helps.
[Edit]
To handle WM_PAINT either call BeginPaint and EndPaint or forward to DefWindowProc
Make sure you are processing the WM_PAINT correctly.
By this I mean make sure you are calling BeginPaint and EndPaint from inside the WM_PAINT message, otherwise you will be confusing Windows into thinking your application still needs to be painted.
May be there is always a message waiting ?
PeekMessage will return 0 only if there are no messages in the message queue. Since there are messages to be dispatched in the message queue, it is returning a non-zero value and your else condition is never executed.