I've fixed this temporarily with a hack; I subclassed the edit control and
stopped WM_KEYDOWN - VK_ESCAPE messages from being sent to it. (Stopping the
WM_CHAR message that follows doesn't work, it's too late by then, WM_CLOSE
is already queued.) But I can't help feeling that I'm missing some
fundamental tenet of message passing (which is more complicated than I ever
imagined, before delving into this problem) and that there is a "right" way
to fix this.
The only other ways to fix this that I've found in many hours of trial and
error nonsense are:
- removing the IsDialogMessage() call from the main message loop. Of course,
with that gone, the TAB key no longer works to move from one control to
another, which is also unacceptable.
- switching to a single-line edit control, which shouldn't make any
difference, really, but it does. I can't use a single line edit control
here, though.
I'd really appreciate any tips on this; I'd love to know if it's
IsDialogMessage() or the edit control's standard WndProc that's sending the
WM_CLOSE - and why. For the escape key, shouldn't I get WM_COMMAND -
IDCANCEL instead? (That's what I get when the input focus is on any other
control and the user pressed Escape.)
I wrote a test application to duplicate the problem in a smaller, simpler
project. It worked - the problem is there too. Here are some possibly
relevant pieces of the code from that test app:
// Main dialog has a private window class, so I need to provide both
// a WndProc (for the RegisterClass() call) and a DialogProc (for the
// CreateDialog() call). My WndProc just calls DefDlgProc,
// because I don't really want to do anything special with the WndProc.
LRESULT CALLBACK MainDlg_WndProc( HWND hwndDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
return DefDlgProc( hwndDlg, uMsg, wParam, lParam );
}
BOOL CALLBACK MainDlg_DlgProc( HWND hwndDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_INITDIALOG:
HANDLE_WM_INITDIALOG( hwndDlg, wParam, lParam, MainDlg_OnInitDialog );
return TRUE;
case WM_COMMAND:
HANDLE_WM_COMMAND( hwndDlg, wParam, lParam, MainDlg_OnCommand );
return TRUE;
case WM_CLOSE:
HANDLE_WM_CLOSE( hwndDlg, wParam, lParam, MainDlg_OnClose );
return TRUE;
case WM_DESTROY:
HANDLE_WM_DESTROY( hwndDlg, wParam, lParam, MainDlg_OnDestroy );
return TRUE;
}
return FALSE;
}
BOOL MainDlg_RegisterWindowClass( void )
{
WNDCLASS wc;
// get info on standard dialog class
GetClassInfo( NULL, MAKEINTATOM( 32770 ), &wc );
wc.lpfnWndProc = MainDlg_WndProc;
wc.hInstance = g_hInst;
wc.hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_PAGER ) );
wc.hbrBackground = (HBRUSH)( COLOR_BTNFACE + 1 );
wc.lpszMenuName = MAKEINTRESOURCE( IDM_MAIN );
wc.lpszClassName = "TESTMAIN";
return ( 0 != RegisterClass( &wc ) );
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nCmdShow )
{
HWND hwndMain;
MSG msg;
g_hInst = hInstance;
MainDlg_RegisterWindowClass();
hwndMain = CreateDialog( g_hInst, MAKEINTRESOURCE( IDD_MAIN ),
NULL, MainDlg_DlgProc );
if ( hwndMain == NULL )
{
return GetLastError();
}
while ( GetMessage( &msg, NULL, 0, 0 ) )
{
if ( !IsDialogMessage( hwndMain, &msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return 0;
}
Many thanks in advance,
John
e-mail: jwk (at) en (dot) com
Oleg
John Kale <jwk@[deletethis]en.com> wrote in message
news:r7Oc3.27$qh1.1...@news.en.com...
No, I'm not sure what the source of the WM_CLOSE message is. Is there
a way to find out (say with Spy++) the source of a message? I'm not
familiar with one. All I know is that my hack (stopping the WM_KEYDOWN
message) solved the problem.
Unfortunately, I am not yet learned in the ways of MFC, so there is no
CDialog class to override or change.
If anyone could refer me to some good material about the ways messages
are passed between control's WndProcs, DefDlgProc, DefWndProc,
IsDialogMessage(), etc, maybe that would be helpful. Mostly what I've
been able to discover is that 1) it's more complicated than I thought
and 2) I still don't understand it all.
Oleg Pilipenko wrote in message
<5vOc3.29$4z5....@iagnews.iagnet.net>...
> Are you positive that it is edit control that sends WM_CLOSE to
> your dialog? It seems more probable that this is default behavior
> of the CDialog class. Try to override OnCancel method of your dialog.
I had the same problem with a richedit control, with no CDialog,
in an essentially Notepad-like app. I solved it by wrapping the
edit control in a child window that ignores the WM_CLOSE.
I have found no explanation for this behaviour. I guess it is
a "bug by design"...
ON
Noooo !
It's not a BUG, it's the normal behaviour for dialogs. It's caused by
The Dialog Manager that is called by IsDialogMessage().
If you hit ESC, it will send WM_CLOSE and return ID_CANCEL
to the parent window.
If you hit RETURN, it will send a WM_CLICK message to the
default Pushbutton (I believe).
You simply have to handle the WM_CLOSE message in your
Dialog Procedure and return TRUE from it to signal the dialog
manager that you have already processed the Message.
Also you have to maintain a flag that is set when you hit the
EXIT button in your dialog form; then, in the response to the
WM_CLOSE message you can return FALSE if the flag is
set to end your program.
HTH
--
Klaus-Werner Konrad
One way to solve this problem is to use a PreTranslateMessage handler in the
dialog and check for WM_KEYDOWN/VK_ESCAPE characters and do not pass these to
the standard dialog. I have used this trick succesfully many times.
The WM_CLOSE is therefor generated not directly by the pressing of an escape
key, but rather by the default behaviour of a dialog. If your dialog is the main
application window you will always have to handle the escape key to prevent
accidental closing.
Hope this helps,
Paul-Erik Raué
Ole Nielsby wrote:
> Oleg Pilipenko <ol...@spammenot.flashline.com> wrote:
>
> > Are you positive that it is edit control that sends WM_CLOSE to
> > your dialog? It seems more probable that this is default behavior
> > of the CDialog class. Try to override OnCancel method of your dialog.
>
> I had the same problem with a richedit control, with no CDialog,
> in an essentially Notepad-like app. I solved it by wrapping the
> edit control in a child window that ignores the WM_CLOSE.
>
> I have found no explanation for this behaviour. I guess it is
> a "bug by design"...
>
> ON
The general consensus seems to be that (1) this is something I'll have
to deal with in a way similar to what I've done (window subclassing,
ignoring WM_KEYDOWN/VK_ESCAPE), and (2) that it's standard behavior,
and intentional.
I'll agree that the standard behavior is for a dialog to close when
the user presses escape. But this is usually acheived by translating
the WM_KEYDOWN/VK_ESCAPE message to WM_COMMAND/IDCANCEL, not by
sending WM_CLOSE. This way, the application behaves exactly as if the
user had pressed the cancel button. That's important, because the
dialog may have code in the IDCANCEL handler that needs to be called
for correct termination of the dialog. That code won't get called if
the dialog just gets WM_CLOSE.
In fact, in my application, the escape key does generate
WM_COMMAND/IDCANCEL if:
- I change the multiline edit control to a single line edit control.
OR
- The input focus is NOT on the multiline edit control
But if the input focus is on a multiline edit control, I don't get
WM_COMMAND/IDCANCEL, I get WM_CLOSE and only WM_CLOSE. There's no way
to tell if the WM_CLOSE came from the system's translation of the
escape key or from the user actually trying to close the application.
It sure sounds to me like the author of the multiline edit control
attempted to emulate standard dialog behavior, and got it slightly
wrong. I don't see how IsDialogMessage() fits in to the mix, in that
case, but this message-passsing scenario is complex.
This kind of thing makes me wish Windows was open-source - then I'd be
able to find out for certain what's going on.
Thanks again, everyone.
John
jwk (at) en (dot) com
Paul-Erik Raué wrote in message <3774C944...@quintiq.nl>...
--
(My return address is intentionally invalid; delete ".---" to get my real address.
My responses are not to be considered official technical support or advice.)