I am using
SetWindowPos(m_hParsent, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE)
to bring the window foreground, but it does not work in XP System, it work well in my win7.
HWND_NOTOPMOST doesn't move a window to the foreground per-se, it simply removes the topmost status from a window that has it, and a side effect of this is that the window will be left above other non-topmost windows. But the docs also say "This flag has no effect if the window is already a non-topmost window."
Use HWND_TOP to specifically move a window to the top of the z-order, or call SetForegroundWindow.
Related
I'm trying to create a dynamic custom control on a resource dialog at runtime which overlaps an already existing control. However, when I do that, it causes a weird artifact.
If I position the new control after the other control in the z-order, my dynamic control is drawn over top of the resource control, as I expected. However, if I click on a spot that is shared between the two controls, it will select the resource control.
If I position the new control before the other control in the z-order, my dynamic control is drawn over by the resource control, again as expected. However, if I again click on the spot that is shared between them, it will select the new control.
What I would have expected is that the control in the top of the z-order would have any clicks directed at them. The actual results are counter intuitive. Why is this happening?
As a code example, I've created an MFC dialog application, where the dialog useds two listboxes to remove any issues with any custom control errors. One listbox is added to the resource with id IDC_LIST1 with member variable name m_dlgResCtrl. The second has the member variable name m_dlgAddedCtrl. The following code is added to the OnInitDialog() member function:
CRect rect;
m_dlgResCtrl.GetWindowRect(rect);
ScreenToClient(rect);
rect += CPoint(20, 20);
m_dlgAddedCtrl.Create(LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
, rect, this, IDC_LIST1 + 1);
m_dlgAddedCtrl.SetFont(GetFont());
// place before resource control in z-order
//m_dlgAddedCtrl.SetWindowPos(m_dlgResCtrl.GetWindow(GW_HWNDPREV), 0, 0, 0, 0
, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
// place after resource control in z-order
m_dlgAddedCtrl.SetWindowPos(&m_dlgResCtrl, 0, 0, 0, 0
, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
// added some text to show overlap
m_dlgResCtrl.AddString(L"Res ctrl");
m_dlgAddedCtrl.AddString(L"Added ctrl");
When placed after res control:
After clicking on shared space:
When placed before res control:
After clicking on shared space:
NOTE: this behavour is not limited to dynamic controls. Just moving the OK button control to overlap the Cancel button control shows the same problem. The OK has a z-order number of 1 and the Cancel of 2. The Cancel shows over top of the OK but when clicked in the overlapping region, the OK is the one that is clicked.
You are confusing z-order and drawing order. They are not necessarily related.
A window that is before another window in the z-order, is above the other window. Reference.
So this code actually positions m_dlgAddedCtrl below m_dlgResCtrl:
// place after resource control in z-order
m_dlgAddedCtrl.SetWindowPos(&m_dlgResCtrl, 0, 0, 0, 0
, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
This code actually positions m_dlgAddedCtrl above m_dlgResCtrl:
// place before resource control in z-order
//m_dlgAddedCtrl.SetWindowPos(m_dlgResCtrl.GetWindow(GW_HWNDPREV), 0, 0, 0, 0
, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
Considering this, the click behaviour in both cases is correct. In the overlapping area, the topmost child window receives the mouse click and gets focused.
Only the drawing order appears incorrect. It may come as a surprise that Windows doesn't automatically respect the z-order when drawing child windows! It just sends WM_PAINT messages to all child windows with a non-empty update region which are then free to draw over each other in whatever order the WM_PAINT messages arrive.
To fix that, simply add the WS_CLIPSIBLINGS style to each child window that may overlap other child windows:
From MSDN:
when a particular
child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style
clips all other overlapping child windows out of the region of the
child window to be updated. If WS_CLIPSIBLINGS is not specified and
child windows overlap, it is possible, when drawing within the client
area of a child window, to draw within the client area of a
neighboring child window.
I'm not sure what I'm doing wrong here. I'm trying to implement a resizing dialog window using MFC. The code is pretty straightforward. I override the following sizing notification:
void CMyDlg::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
//...
//First move the groupbox, pGroupbox is of type CWnd
pGroupbox->MoveWindow(rcGroupbox);
//And then move all radio buttons in it
//Each is moved the exact same way
//pEachRadioButton is of type CWnd
pEachRadioButton->MoveWindow(rcEachRadioButton);
}
But what I get as a result is this.
First here's the initial groupbox:
It happens only when I start dragging the bottom of the main window frame down. I get this artifact:
Note that the radio button positions themselves are correct. If I move the mouse over either of them, it redraws itself correctly (like this "shut-down" button):
Here's the layout of the dialog itself:
IDD_MY_DIALOG DIALOGEX 0, 0, 437, 190
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "My dialog"
MENU IDR_MENU_MAIN
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
PUSHBUTTON "&Cancel",IDCANCEL,381,169,50,14
GROUPBOX "When Tasks Are Completed",IDC_STATIC_WHEN_COMPLETED,7,113,423,36
CONTROL "Close the pro&gram",IDC_RADIO_CLOSE_PROGRAM,"Button",BS_AUTORADIOBUTTON | WS_GROUP,26,129,73,8
CONTROL "Put computer to sleep",IDC_RADIO_SLEEP,"Button",BS_AUTORADIOBUTTON,122,129,84,10
CONTROL "Hibernate computer",IDC_RADIO_HIBERNATE,"Button",BS_AUTORADIOBUTTON,229,129,78,10
CONTROL "Shut down computer",IDC_RADIO_SHUT_DOWN,"Button",BS_AUTORADIOBUTTON,330,129,81,10
DEFPUSHBUTTON "&OK",IDC_BUTTON_SET,311,161,67,22
END
I did some search and found this article, but unfortunately setting those styles did not fix the bug.
Any idea how to fix this?
PS. I'm testing it on Windows Vista, 7, or 8 with visual themes enabled.
When you move a window, the window manager will move the current image of the window as it exists. Unfortunately because you moved the frame first, all those windows got clipped. Flipping them around wouldn't help, because then the tops would get clipped.
The easy way to fix it would be to call InvalidateRect on each control after moving it.
The better way would be to call BeginDeferWindowPos before you start moving anything, then EndDeferWindowPos when you're done so that all the windows move together.
P.S. Windows prefers for the group box to come after the radio buttons in the tab order, that might make a difference too.
I want to bring to front a window(from other application). Currently I'm using:
::SetWindowPos(hwnd, GetForegroundWindow(), 0, 0, 0, 0, SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
It works fine, but in some (unknown to me) cases, it makes the window always on top. According to MSDN, I should use HWND_NOTOPMOST in the place of GetForegroundWindow() but it doesn't work—the window stays under other (not always on top) windows.
How can I bring a window to the front without activating it?
The other application's window can be made temporarily 'top-most' to bring it to front without activating it, first by specifying HWND_TOPMOST as 'hWndInsertAfter' in a SetWindowPos call and then by specifying HWND_NOTOPMOST in a second call (both calls with SWP_NOACTIVATE in 'uFlags'). If there's a risk of removing the top-most style of a window which is already top-most as a consequence of the operation, the WS_EX_TOPMOST ex-style can be tested beforehand with a call to GetWindowLong[Ptr].
If there's a particular window that the other application's window need to be in front (as opposed to being in front of all windows), that window's owner can be set, again temporarily, to the window it needs to be in front. GetWindowLong[Ptr] with GWL_HWNDPARENT can be used to store the window's original owner, then a call to SetWindowLong[Ptr] to set the temporary owner, followed by a call to SetWindowPos with HWND_TOP, and then restoring the original owner with again SetWindowLong[Ptr].
I am trying to use SetWindowPos to put a new opened IE window in the background.
The problem is that it only works after I use put_Visible(VARIANT_TRUE). While the window is not visible, SetWindowPos won't do anything. If I use put_Visible(VARIANT_TRUE) before SetWindowPos this makes the window to appear on top for a second, and then go to the back.
How can I avoid this and make the new window appear in the background without appearing first on top?
Here is what I tried:
HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
using put_Visible(VARIANT_TRUE) before SetWindowPos, and then it works, but it shows on top of all windows before going to the back.
I have a Windows program which has two 2 windows in it:
hwnd (main interface)
hwnd2 (toplevel window, no parent, created by hwnd)
When I double click on hwnd, I need hwnd2 to pop up and show some data, so I use this function to bring hwnd2 to top:
BringWindowToTop(hwnd2);
hwnd2 is brought to top, but there is one thing odd. When I click on hwnd2 again, hwnd (main interface) pops itself up again automatically.
I tried to use the following function to solve this problem, but non of them works.
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
//doesn't work
BringWindowToTop(hwnd2); //This is the function brings hwnd2 to top
SetForegroundWindow(hwnd2); //doesn't work
SetWindowPos(hwnd2, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
//doesn't work
SetWindowPos(hwnd2, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
// hwnd2 "always" on top, not what I want
SetActiveWindow(hwnd2); // doesn't work too (for replying to Magnus Skog, thanks)
SwitchToThisWindow(hwnd2, TRUE);// got the same problem with BringWindowToTop function
SwitchToThisWindow(hwnd2, FALSE);
How could I solve this problem?
Thanks in advance.
(for replying to aJ, hwnd2 doesn't have parent because it needs to be a toplevel window so it can be in front/back of other windows)
(hwnd2 is a media player which is composed of several windows, one of the windows is for video dispaly, two other trackbar controls for progress bar and volume bar, one Toolbar control for control panel.)
(There is one this might help, no matter which window I click on hwnd2, hwnd pops up automatically as loong as "the mouse is on top of hwnd in Z-order", including menu bar and non-client area, etc.)
(This media player is writen in Direct Show. I use IVideoWindow::put_Owner to put video window as the video owner, Direct Show internally creates a sub-video window as a child of the video window. Except for this sub-video window which I can't see the source code, I don't see any thing suspicious in hwnd2.)
I found the reason, which is because of Direct Show. I use multithread to execute it, and then the problem's solved. But...why??
This problem can be resolved by using PostMessage (rather than SendMessage).
try this,it is said coming from M$
HWND hCurWnd = ::GetForegroundWindow();
DWORD dwMyID = ::GetCurrentThreadId();
DWORD dwCurID = ::GetWindowThreadProcessId(hCurWnd, NULL);
::AttachThreadInput(dwCurID, dwMyID, TRUE);
::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
::SetForegroundWindow(m_hWnd);
::SetFocus(m_hWnd);
::SetActiveWindow(m_hWnd);
::AttachThreadInput(dwCurID, dwMyID, FALSE);
In order to bring a window to top, you should get your window handle,thread handle, the windows thread handle who is in foreground
then we attach our thread to foreground window thread and get input by AttachThreadInput, then we set our window z order
to topmost and then restore its z order to normal, call SetForegroundWindow,SetFocus,SetActiveWindow to make sure our window is brought to top and is active and have focus
then deattach the input queue from the old foreground window thread, make our thread the only one who capture the input events
So why should We call AttachThreadInput, it is because
SetFocus sets the keyboard focus to the specified window. The window must be
attached to the calling thread's message queue.
What does AttachThreadInput do?
The AttachThreadInput function can be used to allow a set of threads
to share the same input state. By sharing input state, the threads
share their concept of the active window. By doing this, one thread
can always activate another thread's window. This function is also
useful for sharing focus state, mouse capture state, keyboard state,
and window Z-order state among windows created by different threads
whose input state is shared.
We use SetWindowPos to bring the windows to topmost and show the window if the window is hidding by using SWP_HIDEWINDOW
SetWindowPos function changes the size, position, and Z order of a
child, pop-up, or top-level window. These windows are ordered
according to their appearance on the screen. The topmost window
receives the highest rank and is the first window in the Z order
If your problem is your window is also minimized , you should add one line code to the end
ShowWindow(m_hWnd, SW_RESTORE);
Both work great:
::SetForegroundWindow(wnd)
or
::SetWindowPos(m_hWnd, // handle to window
HWND_TOPMOST, // placement-order handle
0, // horizontal position
0, // vertical position
0, // width
0, // height
SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE// window-positioning options
);
But remember that the last one sets the window always on top.
After many tries and errors.I found following solution to this problem:
SendMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); // restore the minimize window
SetForegroundWindow(hwnd);
SetActiveWindow(hwnd);
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
//redraw to prevent the window blank.
RedrawWindow(hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN );
The hwnd is your windows HWND . Please do not just copy and paste. You also need use GetLastError to check api error after every api call.
I have confirm following result on my win7:
Can restore minimize window and no error return.
If the window already top, the window title will blink and no error return.
If the window has closed, it will return the error "0x578 Invalid window handle."
It can bring the window to the top on all not top-most window and no error return.(For example it will behind the top-most taskmanager)
It do not make the window top-most. The user can make other window on top of it.
SwitchToThisWindow works best for me.
Have you tried SetActiveWindow()?
This will restore an app if minimized and bring it to the front:
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);
//work great!
Var
WndHandle:HWND;
begin
WndHandle :=FindWindowEx(0,0,nil,'Calculator');
PostMessage(WndHandle,WM_SHOWWINDOW,SW_RESTORE,0);
SetForegroundWindow(WndHandle);
end;