The Window Has Been Destroyed, But Still Remains

closed account (zb0S216C)
I created a basic Win32 program that does absolutely nothing useful. Any road, when I click the "X" button, the window vanishes, but in Task Manager, the program name is still there.

Here's my procedure:

1
2
3
4
5
6
7
8
9
switch(e_)
{    
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return(DefWindowProc(h_, e_, wp_, lp_));
}

Ideas?

I'm new to the Win API scene, so I apologise if I'm not specifying anything important. If I am, just ask :)

Wazzak
Welcome to the Dark side Framework!

Clicking the 'X' sends a WM_DESTROY message to the message queue, that's the thing you are polling with GetMessage() in the main body of your execution loop. This will be sent to the registered callback function for that window class and would naturally trigger the case you have in your switch to execute calling the PostQuitMessage() function. This will post a WM_QUIT message to the queue causing GetMessage() to return a 0 normally exiting the while() loop that you have running in the main body of your code, this however does not immediately cause the program to exit. This is still a C\C++ application and it still follows the same rules so if there is anything in the main body holding your application open, like some kind of pause() or sleep() function then the thread will still be running.

Alternatively, if somehow you didn't register your call back function by passing a function pointer to the lpfnWndProc member of your WNDCLASS\WNDCLASSEX struct correctly then your messages might be going somewhere else. This shouldn't happen, it should crash the application when you go to run it but IDE's do some strange things. EDIT: I only mentioned this as a hair brained theory because if the PostQuitMessage() is never called then the program will only destroy the window and not post the WM_QUIT message indicating that it wishes to exit.

EDIT2: WOW, I am rusty at Win32 GUI apps. It's about time for me to refresh myself on this stuff.
Last edited on
My opinion, you should change WM_DESTROY into WM_CLOSE, and as Computergeek01 said, check out your message loop. It should be like:

1
2
3
4
while(GetMessage(...) > 0)
{
    // ...
}

Just check out for that "> 0".
closed account (zb0S216C)
Thanks for the replies :)

@Computergeek01: There's a lot more to a Win32 app's message loop than I initially thought. Your explanation is actually easy to follow. As for the callback, I did register it with WNDCLASSEX::lpfnWndProc before I created the window.

@EssGeEich: I tried changing WM_DESTROY with WM_CLOSE, but the "X" button didn't do anything.

I've noticed that both of you mentioned the use of GetMessage() - a function that appears exactly zero times in my code; I added it. Here's my message loop:

1
2
3
4
5
6
7
8
9
10
11
while(GetMessage(&msg_, nullptr, 0u, 0u) > 0)
{
    if(PeekMessage(&msg_, nullptr, 0u, 0u, PM_REMOVE))
    {
        TranslateMessage(&msg_);
        DispatchMessage(&msg_);
        continue;
    }

    // If there's no message to process, do something useful...
}

I don't know whether this is a good message loop form.

Wazzak
Remove the PeekMessage. It should look like:
1
2
3
4
5
6
7
8
9
10
HWND g_HWND = 0; // This must be a global, initialize this when you receive a WM_CREATE or a WM_INITDIALOG
// OR you can get it from CreateWindow or CreateDialog.
// ... in your entrypoint
// If using dialogs, use CreateDialog here
MSG Msg = {0};
while(GetMessage(&Msg,g_HWND,0,0) > 0)
{
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
}


Or, still if you are using resource dialogs, you can use DialogBox and you need no message loop.

What that message loop does, is process half of the messages ONLY if it has at least two messages on the message pump at the same time. If you only want to use PeekMessage, change GetMessage with PeekMessage, but I think you should hold the "> 0".

EDIT: Just noticed you use CreateWindow. Well, There is no need to use CreateDialog or DialogBox in your actual project. There's only the need for them when using Modeless (Resource) Dialogs.
Also you can use the HWND returned by CreateWindow. Also CreateDialog returns a HWND.
Last edited on
closed account (zb0S216C)
Thanks for the reply, EssGeEich :) I'll make the changes now.

Wazzak
WM_CLOSE generates a WM_DESTROY message when processed by the default window procedure, so processing WM_DESTROY only shouldn't be a problem.

The problem here is PeekMessage as stated by EssGeEich. It removes the WM_QUIT message from the queue and doesn't allow the GetMessage() call to retrieve it, meaning it doesn't allow the while() loop to exit.

Finally note that GetMessage() can now return the value -1 if an error occurs. So it has 3 possibilities: 0 when WM_QUIT is pulled, 1 when some other message is retrieved and -1 when an error occurs. Therefore your loop needs to look like this:

1
2
3
4
5
6
7
8
9
10
11
BOOL ret;
while (ret = GetMessage(&msg, NULL, 0, 0))
{
    if (ret == -1)
    {
        //Process error and possibly exit.
        break;
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
closed account (zb0S216C)
@webJose: So I should only handle WM_DESTROY unless I want something specific to happen when my procedure obtains the WM_CLOSE message?

webJose wrote:
"It removes the WM_QUIT message from the queue and doesn't allow the GetMessage() call to retrieve it, meaning it doesn't allow the while() loop to exit."

I would have never guessed. I'll remove it now.

Noted to GetMessage() possibilities. This Win32 stuff is hard as nails.

Wazzak
Last edited on
Yes, you should only process WM_CLOSE if you need something more/else than what is provided by the default window procedure. For example: The window contains data that the user may want persisted in a file and the current state of this data is DIRTY, meaning it hasn't been saved. You would process WM_CLOSE to make sure the data is saved or the user willingly discards it by means of say, a message box or a task list.

And Yes and No. Win32 stuff is basic and clear in its contents, but I guess its implementation is not so. I guess it is what it needs to be, for better or worse.
closed account (zb0S216C)
OK :) Thanks for all your help, lads :) I appreciate it.

Wazzak
Topic archived. No new replies allowed.