• Advertisement
Sign in to follow this  

Close button not responding.

This topic is 4381 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been writting a game and the client is a windows application. However sometimes when I click the close button (the X in the upper right) the game doesn't close it's self. Going to the system menu and selecting close always works. Additionally, if you move the window around and then click the close button it closes. Does anyone know what's wrong? I'm thinking it must have something to do with the parent window not having focus, but I'm still learning windows programming and haven't been able to track it down.

Share this post


Link to post
Share on other sites
Advertisement
Here's the proc for my parent window


LRESULT CALLBACK CDungeoneerWindow::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage)
{
/* Close window */
case WM_CLOSE:
PostQuitMessage(0);
return true;
break;

case WM_COMMAND:
//Check for child window messages
switch(LOWORD(wParam))
{
case DEF_hSendButton:
GameEngine->vWindowsMessage(DEF_hSendButton);
break;
case DEF_hLoginButton:
GameEngine->vWindowsMessage(DEF_hLoginButton);
break;
case DEF_hRegisterButton:
GameEngine->vWindowsMessage(DEF_hRegisterButton);
break;
}
switch(HIWORD(wParam))
{
case EN_UPDATE:
switch(LOWORD(wParam))
{
case DEF_hChatEdit:
//Get text from the chat edit box
GameEngine->vWindowsMessage(DEF_hChatEdit);
break;
case DEF_hUserNameEditBox:
GameEngine->vWindowsMessage(DEF_hUserNameEditBox);
break;
}
}
return true;
break;

//Connect timer message?
case WM_TIMER:
if(wParam == TIMERID_CONNECT_COMPLETE)
{
// Check if the message is telling us our connection is complete
if(WAIT_OBJECT_0 == WaitForSingleObject( g_hConnectCompleteEvent, 0 ))
{
if( FAILED( g_hrConnectComplete ) )
{
//failed to connect to server, exit program
GameEngine->vConnected(false);
}
else
{
//connection was successful
GameEngine->vConnected(true);
}
KillTimer(m_hWnd, TIMERID_CONNECT_COMPLETE );
}
}
return true;
break;
/* Not handled - let Windows handle */
default:
return DefWindowProc(hWnd, iMessage, wParam, lParam);;
break;
}
return false;
}

Share this post


Link to post
Share on other sites
Hey Procyon I had the same problem so i decided not to put my msg proc in a class I put it in the main file where I had WinMain and it all worked perfect.

Good Luck ^_^

Share this post


Link to post
Share on other sites
This answer will undoubtedly be incomplete, since I cannot find a previous post of mine on the subject, nor can I test your code at the moment, but the documentation states that you must return 0 (FALSE) if you handle WM_COMMAND messages.

You may also want to reorganize your Window Procedure, since you have redundancies such as returns followed by breaks and a return false that will never be reached (the last one).


jfl.

Share this post


Link to post
Share on other sites
cNoob I tried your suggestion, but it didn't help.

I went through my WinProc and fixed up the code, like you suggested jflanglois, but that doesn't seem to have helped either. Here's how the code looks now


LRESULT CALLBACK CDungeoneerWindow::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage)
{
/* Close window */
case WM_CLOSE:
PostQuitMessage(0);
return 0;

case WM_COMMAND:
//Check for child window messages
switch(LOWORD(wParam))
{
case DEF_hSendButton:
GameEngine->vWindowsMessage(DEF_hSendButton);
break;
case DEF_hLoginButton:
GameEngine->vWindowsMessage(DEF_hLoginButton);
break;
case DEF_hRegisterButton:
GameEngine->vWindowsMessage(DEF_hRegisterButton);
break;
}
switch(HIWORD(wParam))
{
case EN_UPDATE:
switch(LOWORD(wParam))
{
case DEF_hChatEdit:
//Get text from the chat edit box
GameEngine->vWindowsMessage(DEF_hChatEdit);
break;
case DEF_hUserNameEditBox:
GameEngine->vWindowsMessage(DEF_hUserNameEditBox);
break;
}
}
return 0;

//Connect timer message?
case WM_TIMER:
if(wParam == TIMERID_CONNECT_COMPLETE)
{
// Check if the message is telling us our connection is complete
if(WAIT_OBJECT_0 == WaitForSingleObject( g_hConnectCompleteEvent, 0 ))
{
if( FAILED( g_hrConnectComplete ) )
{
//failed to connect to server, exit program
GameEngine->vConnected(false);
}
else
{
//connection was successful
GameEngine->vConnected(true);
}
KillTimer(hWnd, TIMERID_CONNECT_COMPLETE );
}
}
return 0;
/* Not handled - let Windows handle */
default:
return DefWindowProc(hWnd, iMessage, wParam, lParam);;
}
}

Share this post


Link to post
Share on other sites
Again, this is a shot in the dark since I cannot test it, but try returning DefWindowProc(...) instead of 0 in your WM_COMMAND case.

Share this post


Link to post
Share on other sites
Ahh im sorry i couldnt help.

Hope it all works out. Good Luck ^_^

Share this post


Link to post
Share on other sites
Quote:
Original post by jflanglois
Again, this is a shot in the dark since I cannot test it, but try returning DefWindowProc(...) instead of 0 in your WM_COMMAND case.


I checked the MSDN documentation and it says that 0 is the correct return value, if you've handled the message.

Share this post


Link to post
Share on other sites
you dont need to handle it in your message proc just when the user clicks the button use te SendMessage function, im a bit rusty but i believe it would go something like this, SendMessage(HWND, WM_QUIT, 0, 0);

dont quote me opn the arguments
*HWND is were your window handle goes (hwnd)*

so instead of taking care of this in the message proc just make your own onclick or notify message and on that occurance send the WM_QUIT message

Share this post


Link to post
Share on other sites
I have test it, and it work very fine to me.
It is would be nice to post the rest of code.

Share this post


Link to post
Share on other sites
Quote:
Original post by C plus noob
you dont need to handle it in your message proc just when the user clicks the button use te SendMessage function, im a bit rusty but i believe it would go something like this, SendMessage(HWND, WM_QUIT, 0, 0);

dont quote me opn the arguments
*HWND is were your window handle goes (hwnd)*

so instead of taking care of this in the message proc just make your own onclick or notify message and on that occurance send the WM_QUIT message


What would I need to test for to find out when the close button had been clicked? All the buttons in my windows I have the Resource IDs for, but I don't know what I would be checking for to find out when the close button was pressed.

Share this post


Link to post
Share on other sites
i had a look at a few of my message pumps and noticed ive never used WM_QUIT: tri changing it to WM_DESTROY: and put PostQuitMessage(0); in the destroy block hope this helps

Share this post


Link to post
Share on other sites
Quote:
Original post by Procyon Lotor
Quote:
Original post by jflanglois
Again, this is a shot in the dark since I cannot test it, but try returning DefWindowProc(...) instead of 0 in your WM_COMMAND case.


I checked the MSDN documentation and it says that 0 is the correct return value, if you've handled the message.
Yes, I know that. I was suggesting you try it anyway because you may not be handling all WM_COMMAND messages, so certain messages will just die without being handled.

Quote:
Original post by Endurion
What does your message pump look like?
Are there any actions inside the pump that might stall the message processing
That's a good question. I would like to see it as well.


jfl.

[Edited by - jflanglois on January 22, 2006 11:08:52 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by cNoob
i had a look at a few of my message pumps and noticed ive never used WM_QUIT: tri changing it to WM_DESTROY: and put PostQuitMessage(0); in the destroy block hope this helps


Well, you are partly right. Although one can use PostQuitMessage() in the WM_CLOSE message handler, it is also done in the WM_DESTROY message as long as the application destroys the window by a call to DestroyWindow() (such as in the WM_CLOSE message handler).


jfl.

[edit] fixed confusion with WM_QUIT.

[Edited by - jflanglois on January 22, 2006 12:22:40 PM]

Share this post


Link to post
Share on other sites
I handle WM_CLOSE by just like such:

WM_CLOSE:
DestroyWindow(hWnd);
return 0;

Then

WM_DESTROY:
// Still need to DestroyWindow(hWnd) in here, but if it's the main window or you want it closed, you need PostQuitMessage before we return!
PostQuitMessage(0);
return 0;

It's actually a lot more complex, it checks to see if it's the main window before posting the quit message. According to MSDN docs WM_QUIT will just give you the number passed in by PostQuitMessage so it's pretty useless to support.

Edit: If you put PostQuitMessage IN WM_QUIT it calls WM_QUIT a second time. Least it did on my XP machine.

Share this post


Link to post
Share on other sites
Ah yes I see what you mean about the way I was handling WM_COMMAND, I changed it so it only returns 0 if the message is actually handled.

I also added WM_DESTROY in, so that it quits on WM_DESTROY or WM_CLOSE. But it still hasn't fixed the problem, something I just noticed is that this is only happening on my computer that is running WinXP Home edition, it works fine on my other computer that is running XP Pro.

What's a message pump? I've never heard that term before.

Thanks for all the help, even though it hasn't fixed my problem yet, you've pointed out a lot of things that I should've fixed.

Here's how my WinProc looks now:

LRESULT CALLBACK CDungeoneerWindow::WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage)
{
/* Close window */
case WM_DESTROY:
case WM_CLOSE:
PostQuitMessage(0);
return 0;

case WM_COMMAND:
//Check for child window messages
switch(LOWORD(wParam))
{
case DEF_hSendButton:
GameEngine->vWindowsMessage(DEF_hSendButton);
return 0;
case DEF_hLoginButton:
GameEngine->vWindowsMessage(DEF_hLoginButton);
return 0;
case DEF_hRegisterButton:
GameEngine->vWindowsMessage(DEF_hRegisterButton);
return 0;
}
switch(HIWORD(wParam))
{
case EN_UPDATE:
switch(LOWORD(wParam))
{
case DEF_hChatEdit:
//Get text from the chat edit box
GameEngine->vWindowsMessage(DEF_hChatEdit);
return 0;
case DEF_hUserNameEditBox:
GameEngine->vWindowsMessage(DEF_hUserNameEditBox);
return 0;
}
}
break;

//Connect timer message?
case WM_TIMER:
if(wParam == TIMERID_CONNECT_COMPLETE)
{
// Check if the message is telling us our connection is complete
if(WAIT_OBJECT_0 == WaitForSingleObject( g_hConnectCompleteEvent, 0 ))
{
if( FAILED( g_hrConnectComplete ) )
{
//failed to connect to server, exit program
GameEngine->vConnected(false);
}
else
{
//connection was successful
GameEngine->vConnected(true);
}
KillTimer(hWnd, TIMERID_CONNECT_COMPLETE );
}
}
return 0;
}
/* Not handled - let Windows handle */
return DefWindowProc(hWnd, iMessage, wParam, lParam);
}

Share this post


Link to post
Share on other sites
The message pump (also message loop) looks something like this:
MSG msg;
while( GetMessage( &msg, window, 0, 0 ) > 0 ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}


I'm not too sure about how you are handling WM_CLOSE and WM_DESTROY. Try changing is to something like this:
case WM_CLOSE:
::DestroyWindow( hwnd );
return 0;

case WM_DESTROY:
::PostQuitMessage( 0 );
return 0;


jfl.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mike2343
I handle WM_CLOSE by just like such:

WM_CLOSE:
DestroyWindow(hWnd);
return 0;

Then

WM_DESTROY:
// Still need to DestroyWindow(hWnd) in here, but if it's the main window or you want it closed, you need PostQuitMessage before we return!
PostQuitMessage(0);
return 0;

It's actually a lot more complex, it checks to see if it's the main window before posting the quit message. According to MSDN docs WM_QUIT will just give you the number passed in by PostQuitMessage so it's pretty useless to support.

Edit: If you put PostQuitMessage IN WM_QUIT it calls WM_QUIT a second time. Least it did on my XP machine.



YAY!!! That fixed it. Thanks sooo much. It must have been that I was never calling the DestroyWindow(). I looked up WM_CLOSE on MSDN and found that the DefWindowProc() calls DestroyWindow(), and I was never doing that because I just called PostQuitMessage(0) straight from the WM_CLOSE message.

Share this post


Link to post
Share on other sites
No problem glad I could help :) I've been battling Win32 for awhile now trying to make my own wrapper (mostly for learning purposes, not to reinvent the wheel). It's a pita :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement