not properly closing from taskbar closing event - c++

if i close my application via Alt-F4, or the corner "X" button, or by posting destroywindow(hwnd) myself, the application closes correctly, and everything works just as expected.
but recently i realized, on windows7, when i close the app by right klicking on the icon in the taskbar, and clicking "Close Window", the window closes, but my app is still running. when debugging, i don't get into either of the WM_QUIT/DESTROY/CLOSE events.
is there some special behavior when closing a window via taskbar? how can i detect that?

You should get WM_CLOSE. Maybe you're getting it on a different window that the one you're expecting? Although that shouldn't be able to happen unless you have multiple top-level windows.

via Alt-F4, or the corner "X" button, or by posting destroywindow(hwnd) myself
You can't post DestroyWindow(). Ensure that the window procedure of your main window resembles this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
// Other cases
//...
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
The PostQuitMessage() function call ensures that your message loop exits, GetMessage() returns FALSE when it receives the WM_QUIT message. This makes your main window behave like the main window, closing it ends the process. You may have other top-level windows that don't, they shouldn't have this WM_DESTROY message handler. DestroyWindow() is already called automatically by DefWindowProc() when it processes the WM_CLOSE message.

Related

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)

WM_KEYDOWN doesn't response

In case WM_KEYDOWN has a messagebox() in order to understand the functionality of this case.
somebody can help me why this case didn't response?
I'm trying to do debugging this while i insert some letter from keyboard and debugger not coming to WM_KEYDOWN case.
Thanks to all!
this is my code:
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_CREATE:
break;
case WM_COMMAND:
break;
case WM_KEYDOWN:
MessageBox(NULL,L"test",L"Information",MB_ICONINFORMATION);
break;
case WM_DESTROY:
// DESTROY WINDOW
break;
default:
return DefWindowProc( hwnd, msg, wParam, lParam );
}
return 0;
}
MessageBox() displays a popup dialog and then runs its own modal message loop to service messages for that dialog until it closes. While the dialog is active, your keystrokes are going to that dialog and not to the window that your WndProc() belongs to. That is why you are not getting more WM_KEYDOWN messages. You should not be using MessageBox() as a debugging tool for UI messages, because it changes the flow of UI messages. Use OutputDebugString() instead. That way, your debugger (or an external viewer like SysInternals DebugView) can display your debug messages without affecting your UI's behavior.

C++: How to set a new wndProc for a console application?

If I have a console application with a handle to it set up like so;
HWND hWnd = GetConsoleWindow();
Then how do I set up a new wndProc for the window?
I tried using
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)conProc);
With conProc being defined as
LRESULT CALLBACK conProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NCHITTEST:
return HTCAPTION;
}
return DefWindowProc(hWnd, msg, wParam, lParam );
}
But it doesn't work and says "Error code: 5 - Access is denied" on GetLastError()
I understand that it's pretty difficult to modify the console application like this, since it's a csrss.exe application and all, but I'd still like to try..
Thanks.
While the impression is that console window belongs to your process (like other window), it is in fact hosted by CSRSS system process and its WndProc is there. This makes you unable to subclass the window and provide your own WndProc living in your process.
Some related reading:
The process that is in charge of displaying the GUI windows in which consoles are presented is... CSRSS
SetWindowsHookEx with WH_KEYBOARD doesn't work for me, what do I wrong?
Subclassing XP Console Window
First of all SetWindowLong is superseded by SetWindowLongPtr, you should use that function.
Are you trying to change the WNDPROC of your own console window or another process?
From the MSDN docs :
GWL_WNDPROC
-4
Sets a new address for the window procedure.
You cannot change this attribute if the window does not belong to the same process as the calling thread.

Viewing Win32 messages

Hello everyone I am new to windows32 programming and I have a couple of questions-:
When I use the following code in a program it works fine -:
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
But when I replace null of GetMessage to hwnd(the handle of the window just created) the doesn't seem to close it still remains running in the background. Why does this happen when I replace NULL with hwnd means I am receiving messages for only one window then why doesn't it work????
while(GetMessage(&msg,hwnd,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
By the way the windows function is-:
LRESULT CALLBACK WinProc(HWND hWnd, UINT message,
WPARAM wparam, LPARAM lparam){
switch(message){
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wparam, lparam);
}
return 0;
}
Secondly-:
Is there any way I can see all the messages sent to any particular window????
Thirdly-:
What is the reason behind writing __stdcall(WINAPI) when compiling my windows programs ????
A quick reply would be appreciated.Thank You.
GetMessage returns 0 (making the loop end) only when it receives a WM_QUIT, but a WM_QUIT is not associated to any particular window, so it is never received if you have a GetMessage that asks only messages for a certain hWnd.
If it's a window of yours, you already see them inside their window procedure; if you want to filter them before dispatching them to their window procedure, you can check the msg structure that is populated by GetMessage before calling DispatchMessage.
The whole Windows API uses the stdcall calling convention (I think because it is slightly faster/produces less boilerplate code than the usual cdecl), so also your callbacks must follow that calling convention. Notice that you must use WINAPI (i.e. stdcall) only on functions that are called by Windows API functions, for the other ones you are free to use whatever calling convention you like best.
PostQuitMessage generates WM_QUIT which is processed by the message queue, but not associated with a particular window. By filtering only hwnd messages in your call to GetMessage, you don't process WM_QUIT.
Regarding seeing all messages being sent to a window / thread / process, see https://stackoverflow.com/questions/4038730/i-am-looking-for-a-windows-spy-application
Finally, regarding __stdcall, see What does "WINAPI" in main function mean?

How to handle keyboard events in a winapi standard dialog?

i don't often work with winapi, i'm writing almost .NET code. But at this time I have to use the winapi to make a simple dialog. There i want to handle some keyevents. Therefore i watched for the corresponding callback message WM_KEYDOWN or WM_KEYUP at MSDN and added it to my callback function.
INT_PTR CALLBACK cbfunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch(message) {
// ...
case WM_KEYUP:
MMsgBox("up"); // I never get here
return 0;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
return 0;
// ...
}
return 0;
}
But neither WM_KEYUP nor WM_KEYDOWN ever get triggered. Then I stated looking for a solution for this problem. I thought may my dialog eats this messages. So I added:
case WM_GETDLGCODE:
return DLGC_WANTALLKEYS;
With the result that it doesn't help.
Other solutions I've found were the following:
Alternatively using the WM_GETDLGCODE event to handle this keys as suggested on here.
I've found a lot of threads (like this one) talking about a method called PreTranslateMessage. But I don't even have got this class, because I simply create my dialog by using DialogBoxParam
So none of them worked for me. In the moment i have got no idea how to handle it. Something I've noticed, is that on key press a WM_COMMAND message seems to occur.
Regards Nem.
According to this link, certain messages are hard to trap with dialog boxes because Windows processes them internally and they never get to the DialogProc. Here are two of the options I can think of:
Use GetAsyncKeyState on a WM_COMMAND event
Create a custom dialog box, the DialogProc for which will handle WM_KEYDOWN etc. messages.
DialogProc doesn't receive WM_KEY events (and many others too). You can:
Subclass the dialog window (overwrite its WndProc) and process all
messages there, sample
Register hot key for the dialog window's HWND and then receive WM_HOTKEY in DlgProc (but registered key combinations will be system-wide)
Create your own message loop, link
Replace This
case WM_KEYUP:
MMsgBox("up"); // I never get here
return 0;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
return 0;
With This
case WM_KEYUP:
MMsgBox("up"); // I never get here
break;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
break;