I have a dialog-based application that displays a fairly small dialog
that is (by default) in the upper left corner of the screen. I recently
added some code that calls MessageBox() when certain conditions are met.
The resulting message box dialog is also rather small and, on a high
resolution screen, may be quite a distance from my application's main
dialog.
I decided that I wanted the message box to be centered on my main
dialog. Since MessageBox() itself doesn't seem to offer any such
facility, I thought I would catch the handle of the message box dialog
by handling a WM_ENTERIDLE message in my dialog. That doesn't work;
MessageBox() doesn't send WM_ENTERIDLE to its parent. So I found that I
could handle the WM_ACTIVATE message (send to my dialog when it is
deactivated) to get the message box dialog handle and center it thus:
case WM_ACTIVATE:
if (wParam==WA_INACTIVE)
if (GetParent((HWND)lParam)==hDlg) {
GetWindowRect((HWND)lParam, &rect);
width = rect.right-rect.left, height = rect.bottom-rect.top;
GetWindowRect(hDlg, &rect);
rect.left = (rect.right-rect.left-width)/2;
rect.top = (rect.bottom-rect.top-height)/2;
ClientToScreen(hDlg, (LPPOINT)&rect);
SetWindowPos((HWND)lParam, HWND_TOP,
rect.left, rect.top, 0, 0,
SWP_NOSIZE
); }
return FALSE;
This works (the message box dialog is centered on my dialog) but causes
the following strange behavior:
HERE IS THE PROBLEM
When this code is used, the dialog window (the parent of the message
box) repaints its caption bar to reflect the fact that it is no longer
the active window. When it does this it fails to redraw the text of the
caption so the caption bar is blank except for its icon (if it has one)
and its minimize/maximize/close buttons.
If any portion of the caption bar is invalidated (as by moving another
window over it and then moving the window away) any portion of the
caption text in the invalidated area is redrawn. And when the window
again becomes active the caption is redrawn.
I found that I can prevent this behavior by posting a private message to
my window and calling SetWindowPos() when that message arrives, rather
than in the handler for WM_ACTIVATE.
Another interesting note: this problem does not appear in Windows ME.
Any thoughts on what's happening here?
Norm
--
--
To reply, change domain to an adult feline.
I don't know why strange effect with caption appears. But, before
we'll delve into gory details of windowing, let me ask you one
question. Are you sure that you pass correct owner window handle to
MessageBox? I tried to call MessageBox from simple application
providing app's window as owner. MessageBox always correctly position
itself in center of owner's rectange. However, if I specify NULL (i.e.
desktop window) as owner, then message box appears in the center of
desktop.
Here's excellent blog entry of Raymond Chen about modal dialog boxes:
"Modality, part 4: The importance of setting the correct owner for
modal UI"
http://weblogs.asp.net/oldnewthing/archive/2005/02/23/378866.aspx
Here's the complete source for the application. Remove the code that
handles WM_ACTIVATE to see the message box in the center of the screen.
Or change the WM_ACTIVATE handler so that it posts a private message and
center the message box (using the same code) in that handler to fix the
caption problem.
Norm
#include <windows.h>
#include "resource.h"
HINSTANCE hinstApplication;
BOOL CALLBACK MainDialog(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{ int height, width;
RECT rect;
switch (wMsg) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_BUTTON1:
MessageBox(hDlg, "This is the text", "Caption",
MB_DEFBUTTON1|MB_ICONINFORMATION|MB_OK
);
break;
case IDCANCEL:
EndDialog(hDlg, 0);
break;
default:
return FALSE; }
break;
case WM_ACTIVATE:
if (wParam==WA_INACTIVE)
if (GetParent((HWND)lParam)==hDlg) {
GetWindowRect((HWND)lParam, &rect);
width = rect.right-rect.left, height = rect.bottom-rect.top;
GetWindowRect(hDlg, &rect);
rect.left = (rect.right-rect.left-width)/2;
rect.top = (rect.bottom-rect.top-height)/2;
ClientToScreen(hDlg, (LPPOINT)&rect);
SetWindowPos((HWND)lParam, HWND_TOP,
rect.left, rect.top, 0, 0,
SWP_NOSIZE
); }
return FALSE;
case WM_INITDIALOG:
SendMessage(hDlg, WM_SETICON, ICON_BIG,
(LPARAM)LoadImage(hinstApplication,
MAKEINTRESOURCE(BLACK_CAT), IMAGE_ICON,
32, 32, LR_DEFAULTCOLOR
)
);
SendMessage(hDlg, WM_SETICON, ICON_SMALL,
(LPARAM)LoadImage(hinstApplication,
MAKEINTRESOURCE(BLACK_CAT), IMAGE_ICON,
16, 16, LR_DEFAULTCOLOR
)
);
break;
default:
return FALSE;
}
return TRUE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd
)
{ DialogBox(hinstApplication = hInstance, MAKEINTRESOURCE(MAIN_DIALOG),
NULL, MainDialog
);
return 0;
HHOOK hCBTHook;
LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam)
{
LPCBT_CREATEWND lpCreateWnd;
if ( nCode >= 0 )
{
switch (nCode)
{
case HCBT_CREATEWND:
{
RECT Rect, ScreenRect;
int nX, nY;
lpCreateWnd = (LPCBT_CREATEWND) lParam;
SystemParametersInfo(SPI_GETWORKAREA,0,&ScreenRect,0);
HWND hWndOwner =
(lpCreateWnd->lpcs->hwndParent!=NULL?lpCreateWnd->lpcs->hwndParent:GetDesktopWindow());
GetWindowRect(hWndOwner,&Rect);
nX = Rect.left +
((Rect.right-Rect.left)-lpCreateWnd->lpcs->cx)/2;
nY = Rect.top +
((Rect.bottom-Rect.top)-lpCreateWnd->lpcs->cy)/2;
if (nX < 0)
nX = 0;
else if ((nX + lpCreateWnd->lpcs->cx) >
ScreenRect.right)
nX = ScreenRect.right -
lpCreateWnd->lpcs->cx;
if (nY < 0)
nY = 0;
else if ((nY + lpCreateWnd->lpcs->cy) >
ScreenRect.bottom)
nY = ScreenRect.bottom -
lpCreateWnd->lpcs->cy;
lpCreateWnd->lpcs->x = nX;
lpCreateWnd->lpcs->y = nY;
UnhookWindowsHookEx(hCBTHook);
}
break;
return 0;
}
}
return nCode < 0 ? CallNextHookEx(hCBTHook, nCode, wParam,
lParam) : 0;
}
int CenteredMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption,
UINT uType)
{
hCBTHook = SetWindowsHookEx(WH_CBT, CBTProc, NULL,
GetCurrentThreadId());
return (MessageBox(hWnd, lpText, lpCaption, uType));
As cast...@club-internet.fr suggested SWP_NOACTIVATE solves the
problem.
I always pass the handle of my main window and MESSAGE-BOX never centers
within it.
--
-GJC [MS Windows SDK MVP]
-Software Consultant (Embedded systems and Real Time Controls)
- http://www.mvps.org/ArcaneIncantations/consulting.htm
-gcha...@mvps.org
>
>"Alex Blekhman" <tkfx^N05P4M^@yahoo.com> wrote in message
>news:392mhgF...@individual.net...
>>
>> I don't know why strange effect with caption appears. But, before
>> we'll delve into gory details of windowing, let me ask you one
>> question. Are you sure that you pass correct owner window handle to
>> MessageBox? I tried to call MessageBox from simple application
>> providing app's window as owner. MessageBox always correctly position
>> itself in center of owner's rectange. However, if I specify NULL (i.e.
>> desktop window) as owner, then message box appears in the center of
>> desktop.
>
> I always pass the handle of my main window and MESSAGE-BOX never centers
>within it.
And I'm pretty sure I pass the handle of my main window and MessageBox
almost always centers to the screen. Except that sometimes it pops up
near the bottom right corner after I've been debugging for a while.
This may depend on the precise set of styles we use, so I'll say that
I use
MB_TOPMOST | MB_APPLMODAL | MB_SETFOREGROUND
plus MB_OK or one if its relatives.
(Yes, these are rather self-centered of me, but my applications are
usually meant to be the only programs running.)
-----------------------------------------
To reply to me, remove the underscores (_) from my email address (and please indicate which newsgroup and message).
Robert E. Zaret, eMVP
PenFact, Inc.
500 Harrison Ave., Suite 3R
Boston, MA 02118
www.penfact.com
I did a test earlier with just MB_OK and it centered on the desktop.
The bit about "lower right hand corner" is because it moves a little down
and to the right each time it's called to make sure it doesn't obscure the
earlier one.
Yes, my fault. I tested it with MFC based application first. MFC hooks
all window creations in app and calls CWnd::CenterWindow for dialog
boxes. Non-MFC based application behaves as you described.
> Your hook procedure looks like a lot of code to solve something that can
> be solved more easily, either the way I've done it or with SWP_NOACTIVATE.
Yes, but there is also the tests on screen bounds.
The message box could be off screen... (only a few chances, I agree)
>
><r_z_aret@pen_fact.com> wrote in message
>news:thbp21h3kh6mkurbm...@4ax.com...
>> On Mon, 7 Mar 2005 13:37:47 -0500, "Gary Chanson"
>> <gcha...@No.Spam.TheWorld.net> wrote:
clip
>>
>> And I'm pretty sure I pass the handle of my main window and MessageBox
>> almost always centers to the screen. Except that sometimes it pops up
>> near the bottom right corner after I've been debugging for a while.
clip
>
> The bit about "lower right hand corner" is because it moves a little down
>and to the right each time it's called to make sure it doesn't obscure the
>earlier one.
Ah! The solution to one of life's little mysteries. Thank you.
I've never noticed that the MessageBox moves slightly each time. But
that's probably because I don't pop up many unless I get into some
weird loop; and then I might get many so it would seem to move
suddenly.
Your welcome. I'm glad to share a bit of enlightenment when possible.