The default way of handling the lifetime of windows in Windows is listening for a WM_CLOSE message, then deciding whether to close the window or not and optionally processing the WM_DESTROY message (for cleanup etc.) afterwards.
Is there any scenario where WM_DESTROY could be sent without WM_CLOSE beforehand? I mean "by the system", not by manually calling DestroyWindow() or PostMessage(). Or is it safe to rely on WM_CLOSE always being sent before WM_DESTROY?
Yes. If you create a MFC dialog based application and press "Cancel" button (IDCANCEL as the ID), it doesn't send WM_CLOSE event. Also if you press "Esc" key, same thing.
If you click "X" button on the upper-right corner of the dialog box, yes WM_CLOSE will be sent, though.
In the WM_COMMAND section of a Dialogex message loop it's possible to add a case for WM_DESTROY. This case captures an Escape keydown by default, so by adding an accompanying EndDialog statement in the VK_ESCAPE condition, we can then initiate a PostQuitMessage.
Edit: There's a clearer explanation here.
Related
In MFC, suppose I have a dialog box, and in this box, it has a child CListCtrl, then I use mouse to click this CListCtrl, we know that eventually an WM_LBUTTONDOWN message is sent to CListCtrl. My question is: How does this WM_LBUTTONDOWN message get there?
Two possibilities:
Dialog box first gets this WM_LBUTTONDOWN message , and it finds that mouse click occurs in its child window, then it forwards this message to CListCtrl.
CListCtrl first gets this WM_LBUTTONDOWN message, it can process this message, and if it doesn't care it will forward this message to parent window, i.e. dialog box for further processing.
Which one is true?
Thanks.
Input messages are never sent to a window. They are posted to the message queue associated with a window, waiting to be retrieved through one of the message retrieval functions (GetMessage, PeekMessage, etc.).
Depending on whether the dialog box is modal or modeless, messages are retrieved by the nested modal loop (for modal dialogs) or the application's message loop. The message is then passed on to DispatchMessage, to find the recipient (starting from the topmost visible window under the mouse pointer, that is neither disabled nor transparent), and call into the associated window's window procedure. The window procedure can decide, whether it handles the message or not. A window procedure typically calls DefWindowProc to perform default processing, if it doesn't handle a message.
To summarize: The application's message loop (or the nested modal message loop) gets to see the message first, and instructs the window manager to deliver the message to the respective recipient.
A thorough description on Windows message processing is available at About Messages and Message Queues. The description is specific to the Windows API. Since MFC is just a wrapper around the Windows API, the contents apply to MFC as well, even though some of the concepts are hidden in a typical MFC application.
I am using Visual Studio 2005 with MFC and Windows 7. I have an application with many dialog windows.
I use OnSysCommand to check for SC_CLOSE messages and check the lParam to determine if this is initiated from the task bar or the close button on the dialog. But how can I determine whether a close message is a "close all windows" from the task bar or just closing an individual dialog from the task bar?
Thanks
I don't think that you get this solved with a single message.
When you Close the application you have to distinguish also between a mouse action and Alt+F4
If you close the application with Alt+F4 the message looks identical like closing it from the task bar (Look at the lParam value)
You can look at the last message that was retrieved with GetMessage (the last input message). If the message comes from the task bar it is a posted WM_SYSCOMMAND. If the message comes from the inside you receive the WM_SYSCOMMAND as SendMessage.
You can use AfxGetCurrentMessage to determine what was the last input message. If you find WM_SYSCOMMAND here the close comes from the taskbar. If you find a keyboard or mouse message here the message comes form the user input.
Tip: Use Spy++ to examine this behavior.
I think you can differentiate as follows:
Closing a windows using the system menu 'Close' generates a WM_SYSCOMMAND where wParam= SC_CLOSE and lParam!=0.
Closing the window using Alt+F4 or "Close all windows" both generate a WM_SYSCOMMAND with a wParam=SC_CLOSE and lParam=0.
However, Alt+F4 generates a WM_SYSKEYDOWN message with wParam=VK_F4 beforehand.
I wanted to ignore the "Close all windows", whilst using Alt+F4 and the 'Close' menu. I therefore caught Alt+F4 in WM_SYSKEYDOWN and posted a WM_CLOSE message. I then ignored any WM_SYSCOMMAND message with wParam=SC_CLOSE and lParam=0.
I'm having a problem receiving message in WM_KEYDOWN. WM_KEYDOWN works just fine until I click any button in my app. From that point it no longer receives my input from the keyboard. How to fix it?
If you are using Win32 controls such as CreateWindowEx(NULL, L"BUTTON", ... this is expected Each control is actually a child window and is capturing all of the window messages after it has focus.
Once the button is clicked you can capture the WM_COMMAND - BM_CLICK message to then call SetFocus(hwnd) to refocus on your window (as Giswin mentioned).
Probably your window has no focus before you click any button on your app. you can add code somewhere in your app to set focus programmatically:
yourwindow->SetFocus();
or use winapi:
::SetFocus(hWnd);
Just in case anyone is wondering, I (unsurprisingly) noticed the same behavior for handling WM_CHAR responses in my WindowProcedure callback as well. As soon as you click a button, the focus changes from the main window to the button control (which is a child window) and keyboard presses no longer have any effect.
As suggested by #NTSCCobalt, adding a simple SetFocus(main window handler) in your WM_COMMAND cases will solve the problem, e.g.
case DEL__BUTTON:{
<Button specific code>
SetFocus(hwnd);
return 0;
}
Does anyone know the WM_MESSAGE that is sent when a window has been maximized (either by the maximize button being pressed in the title bar, or by double clicking the title bar?)
Is there a windows message for the maximize button being pressed?
Win32/C++, thanks.
You get the WM_SIZE message with the value SIZE_MAXIMIZED in wParam
Edit
The #jamesdlin comment bellow called my atention to WM_WINDOWPOSCHANGED documentation, which states (emphasis mine):
Remarks
By default, the DefWindowProc function sends the WM_SIZE and WM_MOVE messages to the window. The WM_SIZE and WM_MOVE messages are not sent if an application handles the WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient to perform any move or size change processing during the WM_WINDOWPOSCHANGED message without calling DefWindowProc.
Thanks james!
I dealt with this recently, and the approach I settled on was to check IsZoomed in response to WM_WINDOWPOSCHANGED, comparing its result to the previous one to detect when a transition occurs, and then to forward WM_WINDOWPOSCHANGED to the default window procedure.
If you have complete control over the message handling in your application and know that there isn't (and won't ever be) a WM_WINDOWPOSCHANGED handler that suppresses WM_MOVE/WM_SIZE, then you should be able to handle it directly in a WM_SIZE handler as described in jachguate's answer.
I was wondering what the difference between the WM_QUIT, WM_CLOSE, and WM_DESTROY messages in a windows program, essentially: when are they sent, and do they have any automatic effects besides what's defined by the program?
They are totally different.
WM_CLOSE is sent to the window when it is being closed - when its "X" button is clicked, or "Close" is chosen from the window's menu, or Alt-F4 is pressed while the window has focus, etc. If you catch this message, this is your decision how to treat it - ignore it, or really close the window. By default, WM_CLOSE passed to DefWindowProc() causes the window to be destroyed.
WM_DESTROY is sent to the window when it starts to be destroyed. In this stage, in opposition to WM_CLOSE, you cannot stop the process, you can only make any necessary cleanup. When you catch WM_DESTROY, none of its child windows have been destroyed yet.
WM_NCDESTROY is sent to the window when it is finishing being destroyed. All of its child windows have been destroyed by this time.
WM_QUIT is not related to any window (the hwnd got from GetMessage() is NULL, and no window procedure is called). This message indicates that the message loop should be stopped and the application should exit. When GetMessage() reads WM_QUIT, it returns 0 to indicate that. Take a look at a typical message loop snippet - the loop is continued while GetMessage() returns non-zero.
WM_QUIT can be sent by the PostQuitMessage() function. This function is usually called when the main window receives WM_DESTROY (see a typical window procedure snippet).
First of all, the WM_CLOSE and WM_DESTROY messages are associated with particular windows whereas the WM_QUIT message is applicable to the whole application (well thread) and the message is never received through a window procedure (WndProc routine), but only through the GetMessage or PeekMessage functions.
In your WndProc routine the DefWindowProc function takes care of the default behavoir of these messages. The WM_CLOSE messages requests that the application should close and the default behavoir for this is to call the DestroyWindow function. Its when this DestroyWindow function is called that the WM_DESTROY message is sent. Notice that the WM_CLOSE is only a message requesting that you close (like WM_QUIT) - you don't actually have to exit/quit. But the WM_DESTROY message tells you that your window IS being closed and destroyed so you must cleanup any resources, handles etc.
Just so it doesn't get lost in the comments... don't forget about WM_CANCEL. When you click the close (x) button on an MFC dialog, it will certainly send WM_CLOSE. The default OnClose() function will then call the default (base class) OnCancel() function.
However, if you simply type the ESC key, this will lead to the closure of the dialog, but (as far as I can tell) without generating the WM_CLOSE event - it goes directly to the WM_CANCEL/OnCancel() mechanism.
I hereby invite the community to elaborate on this... or edit that elaboration into the accepted answer.
At first let's discuss WM_QUIT - the difference from another messages that this is not associated with window. It is used by application. For example this can be handled by non-visible standalone OLE server (.exe, but not in-proc as .dll)
WM_CLOSE - per msdn: "An application can prompt the user for confirmation, prior to destroying a window" - it is used as notification about intention to close (you can reject this intention).
WM_DESTROY - is a fact that window is closing and all resources must(!) be deallocated.
I know this is old, but just trying to provide a clearer answer for anyone.
// What causes each message?
WM_CLOSE: // Pressed Close Button (X) / Alt+F4 / "Close" in context menu
WM_DESTROY: // Called DestroyWindow(hwnd)
WM_QUIT: // Called PostQuitMessage(exit)
// What do they do by default?
case WM_CLOSE: DestroyWindow(hwnd); return 0; // pressed close? destroy window.
case WM_DESTROY: PostQuitMessage(0); return 0; // destroyed window? quit message loop.
// WM_QUIT isn't associated with a window, so isn't sent to the window procedure
So WM_CLOSE is just so we can request to destroy the window. However you might want it to show a popup in your game asking if you're sure. (and if you want to save first)
And WM_DESTROY doesn't actually post the quit message by default, since you could have multiple windows. That's just the usual event we quit after. You could have WM_CLOSE call PostQuitMessage(exit) and destroy your window(s) after the message loop if you wanted.
If you wanted a custom close button in your game, it should do what WM_CLOSE does.
Also there is the function CloseWindow(hwnd), however it simply minimizes the window.
Hope this helps anyone.