How to bring other app window to front without activating it? - c++

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].

Related

Positioning dynamically created control that overlaps another control in a resource dialog causes odd behaviour

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.

Why HWND_NOTTOPMOST cannot bring the window foreground in xp?

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.

Create a window using the WS_EX_NOACTIVATE flag ,but it can't be dragged until I release the mouse

I have created a window using the WS_EX_NOACTIVATE flag and it works great as far as not taking focus when you click the window. However when I drag the window or try to resize it, it doesn't redraw the window as your are moving and resizing it, only at the very end once you release the mouse button. Is there a way around this? I would like to see the window as I am resizing it. I have searched many documents, but I still don't find the resolution...
If you need a window that doesn't take focus when clicked, but can still be interacted with, you need to handle the WM_MOUSEACTIVATE, and return MA_NOACTIVATE.
Additional information and fully working sample code has been published by Raymond Chen. See How can I have a window that rejects activation but still receives pointer input?
It's a Windows bug. You need to call SetWindowPos(hwnd, 0, x, y, width, height, 0) on WM_MOVING. The coordinates to set are given to you in lParam which is a RECT*.
Note that doing this will activate the owned window and deactivate the owner, which is not what you want (and SWP_NOACTIVATE has no effect either).
To avoid that, you need to set WS_CHILD on the owned window. But set it after you created the window, via SetWindowLong(), otherwise your owned window will get clipped, like any child window.
And, as you probably already figured out, this only works for windows with WS_EX_TOOLWINDOW ex style. I wasn't able to make the owned window stay deactivated with any other style combination that doesn't include WS_EX_TOOLWINDOW.
That's winapi for you :(

Floating/Always above dialog

I've noticed in GIMP that when a dialog is opened it does not disable the parent window. The parent window can still be used, while the child window floats in front of it.
I want to do the same thing, how ever for me when I click on my parent window it pushes the children to the back, such that the parent comes to the front.
I'm using Qt QDialog's but happy to do platform specific code to get this working.
I've been looking here:
http://msdn.microsoft.com/en-us/library/ff700543(v=vs.85).aspx
but nothing seems to do what I'm after. I have a dodgey solution currently where I set the window to HWND_TOPMOST when my app receives focus, then disable this when it looses focus, but its not ideal as message boxes are being pushed behind these top most windows.
ie.
SetWindowPos(winId(), stayOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOACTIVATE);
Looks like I didnt have parenting setup correctly on my dialog! It needed to be parented to the parent dialog/main window and then it just works.
You need to call setWindowFlags() including the Qt::WindowStaysOnTopHint flag.

SetWindowPos doesn't work with put_Visible(false)

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.