I need the ability to set the window not only z-type (always top/always bottom/etc.), but also z-index (0..+inf.).
Windows with smaller z-index values should be lower than windows with greater.
I know about SetWindowPos and it`s parameter hWndInsertAfter, using it I can achieve what I want, but this way seems too complicated.
Is there better solution ?
The windowing subsystem maintains the Z-Order, implemented as a list:
The system maintains the z-order in a single list.
You can move windows in this list (by calling SetWindowPos for example), passing the previous window as an index, or HWND_TOP to move a window to the front. There is no API that uses an ordinal as the index.
If you need to insert a window ahead of another window, call GetNextWindow(GW_HWNDPREV) first to be passed as the hWndInsertAfter. If there is no window ahead in the z-order, GetNextWindow returns NULL, which conveniently maps to HWND_TOP.
Related
So yes, I find myself in the dubious position of implementing a SwitchToThisWindow call to force my window to the front. I agree, its not ideal, but its not always possible to argue against product "features" that others deem necessary.
Now, I consider SwitchToThisWindow to be a win over the AttachThreadInput hack to do a forced window switch as its less likely to deadlock, and should SwitchToThisWindow be removed, or cease to function I won't complain.
However, SwitchToThisWindow has the unfortunate side effect of pushing the current foreground window to the bottom of the z-order in addition to bringing the target window to the top when FALSE is passed for the fAltTab parameter, and not doing anything if TRUE is passed.
How can I avoid this 'push current active to z-bottom' behavior without resorting to AttachThreadInput?
Alternatively, MS can just remove AttachThreadInput as a viable workaround and I can just tell my manager that the impossible, is in fact, actually, impossible.
I don't know if this helps, but the only way i found out to bring my window to top reliably is to make the following 2 calls:
ShowWindow(myhwnd, SW_MINIMIZE);
ShowWindow(myhwnd, SW_RESTORE);
Obviously these calls only should be made, when your window currently is not the topmost one in order to avoid flickering. But this also should not have the side effect of bringing the current front window to the bottom of the z order.
When passing fAltTab=FALSE you are actually emulating Alt+Esc. So you could reverse this z-order change with SetWindowPos and its hWndInsertAfter after the SwitchToThisWindow call, but then you are back in ugly hacky-land IMHO.
The question is, do you really need keyboard focus?
Let me suggest another alternative:
If your window is minimized, restore it
Set your window to be topmost, when your window is activated remove the style again.
Call SetForegroundWindow to flash the taskbar button (Or FlashWindowEx)
This should avoid the scenario where a user is typing and ends up performing some action in your UI without even looking at the screen.
Edit:
HWND hwndFgnd=GetForegroundWindow();
SetWindowPos(hwnd,hwndFgnd,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
SetWindowPos(hwndFgnd,hwnd,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
..will probably work if you don't want to set the topmost bit at any point (Even if your window is at the top of the z-order, you still can't legally get the focus with SetForegroundWindow)
This is a bad problem I faced too. See my solution here. It works both for Show() and ShowDialog().
I never knew this, but apparently:
By default, the system reduces a
minimized window to the size of its
taskbar button and moves the minimized
window to the taskbar. A restored
window is a window that has been
returned to its previous size and
position, that is, the size it was
before it was minimized or maximized.
In an application, we want to save the position/size of various windows at exit. This leads to a problem for minimized windows. Our solution is to restore all windows before running the save-state logic, but that just seems hacky. Is there a better way?
How about using GetWindowPlacement?
That returns a WINDOWPLACEMENT structure that contains information about the window's coordinates in the restored position.
Remember that (as Leo Davidson points out in the comments) that you must respect the difference between workspace and screen coordinates. As the WINDOWPLACEMENT documentation explains:
The coordinates used in a
WINDOWPLACEMENT structure should be
used only by the GetWindowPlacement
and SetWindowPlacement functions.
Passing workspace coordinates to
functions which expect screen
coordinates (such as SetWindowPos)
will result in the window appearing in
the wrong location. For example, if
the taskbar is at the top of the
screen, saving window coordinates
using GetWindowPlacement and restoring
them using SetWindowPos causes the
window to appear to "creep" up the
screen.
Or, the simpler solution that I've no doubt used before is just to check if the window is minimized before saving the state, and if it is, skip saving any state information.
As far as explaining why a window changes its size when it gets minimized, Raymond Chen's blog entry (and the linked entry as well) on the subject is mandatory reading. They don't really change to their taskbar button's size, but rather to a pre-defined size of 160x31. He explains that you can see this by minimizing a MDI child window into its parent—that's really its size.
Handle WM_SIZE message. If wParam is not SIZE_MAXIMIZED or SIZE_MINIMIZED, keep window size and position in some varibles. Use these variables when window is closed.
The GetClientRect function, according to MSDN, is actually only good for determining the client width & height, since left & top are always zero. Is there a way to get the complete client coordinates, including left & top (either in screen space, or in window space)?
Call ClientToScreen on the top left and bottom right of the returned RECT. If you're using MFC, CWnd has a helper overload of CWnd::ClientToScreen that will do this transparently for you.
Maybe you are needing GetWindowRect.
You're looking for the GetWindowPlacement function. This function returns a WINDOWPLACEMENT struct which has an rcNormalPosition property which specifies the window's position when it is in the normal (rather than maximized or minimized) display state.
EDIT: itowilson's answer is actually cleaner because the WINDOWPLACEMENT structure also contains a bunch of data you don't need.
In Windows, is it possible to set window A such that it is always on top of window B, yet allow other windows to work as normal and appear over the top of both, when active.
In other words, I want a parent-child relationship between two windows. Can this be done without making window A a child of window B, MDI-style? Window B isn't mine (Internet Explorer), and screws my dialog A's graphics up when I try to achieve this with SetParent.
I thought I'd cracked it with this idea from an MSDN forum post, but alas windows A is still always on top of everything, not just window B.
// Place window A on top
SetWindowPos(hWndWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
// Place window B underneath it
SetWindowPos(hWndParent, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
Is it possible?
Wouldn't creating an ownership relationship do the trick?
SetWindowLong(hwndChild, GWL_HWNDPARENT, hwndOwner)
The windows can be in different processes and you can call this from any process. This will ensure that the child window is always above the owner window. This is different than SetParent which actually creates a Parent / Child relationship. Read through this article (its from 1993 but still mostly correct) to see the distinction between ownership and parenting.
When your window's Z-order (or size or position) is changing, it should receive a WM_WINDOWPOSCHANGING message. If you process that message, you have an opportunity to modify the final Z-order (or size or position) to which the window is moved.
To illustrate, in hWndA's window procedure:
case WM_WINDOWPOSCHANGING:
DefWindowProc(hWnd, msg, wParam, lParam);
WINDOWPOS *p = (WINDOWPOS*)lParam;
p->hwndInsertAfter = hWndB;
p->flags &= ~SWP_NOZORDER;
return 0;
should insert hWndA after hWndB in the Z-order any time hWndA's position changes.
Until Vista, one way to do it would have been to use SetWindowsHookEx, and hook the WH_CBT or WH_CALLWNDPROC hook, and then take appropriate action when you detect the Z order changing. However this doesn't work with Vista (as far as I can tell from googling).
The only other solution I can think of is to set up a timer to fire every few seconds, and then when you receive a WM_TIMER, you interrogate the system using GetNextWindow to find out which window is behind yours. If it's not IE, then call SetWindowPos to position your window above IE (I assume you have a HWND for the IE window you care about - remember there can be multiple IE windows).
This will cause problems if people try to bring your window to the front - it will flip back to being just above IE. In this case, in your code you could handle WM_ACTIVATE and try to change the Z-order of IE's window so it's below your window (call SetWindowPos to move IE's window so it's above the window that is currently below your window). This solution may be fraught with problems as Windows may try to prevent you messing with the windows of another process, for security reasons. On the other hand, the MSDN docs for SetWindowPos don't explicitly mention that you can't manipulate the windows of another process. There may be obscure limitations though.
Even with this timer hack, you're going to effectively have a busy-waiting loop in your app (with the frequent WM_TIMER messages) and this is generally a bad thing to do, especially for battery life of laptops etc. (because you prevent the CPU from entering a sleep state, and so on).
I'd say there's no good way of doing this, and anything you're likely to get working will be brittle and cause problems. I strongly recommend not trying to do it. Is it possible to make your program into some kind of plug-in or toolbar for IE instead?
NB Be particularly aware that SetWindowsHookEx imposes a performance penalty at a system-wide level if you go down this route.
Maurice's answer is the best out of what's here but is missing an important step. When you call show on your window that you want as the overlay, you need to call the show method that has the parameter. You'll need to define a class that implements the IWin32Window interface and just make a new instance of that. The only thing that interface cares about is the Handle so just set that to the handle of the IE window and it should work pretty well
If the parent-child relationship is made by yourself with the SetWindowPos() function, your desire can be implemented.
Can you access the Z-order of the windows?
I cannot recall the default z-order of windows, but I think it is 1. You might be able to set IE to a -1 and your app to 0.
Try this:
// Place window A on top of window B
SetWindowPos(hWndA, hWndB, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
The second window handle parameter specifies the next window down in the Z order.
Note this doesn't actually change the window parent-child relationships - but you can simulate it.
I'm writing a screen recording app for Windows in Delphi 7 and wish to know when the mouse pointer changes in my app (like from a normal pointer to a resize pointer, etc).
Currently what I'm doing is painting the mouse pointer onto an in-memory bitmap everytime the mouse moves (and on a timer) and doing a pixel by pixel comparison of it with the last bitmap I painted.
Though the comparision is fairly quick (about 2-5ms) because it's happening so often (every mouse move) it adds up. I figure there has to be a faster and less complicated way!
You have a handle to the cursor, right? If it's the same handle value you had before, then I think it's reasonable to assume it looks the same, too. If the cursor looks different, it will have a different handle value.
That should certainly be true for the standard system cursors. If the application you're recording is creating new cursors while it's running, then maybe it would be able to update the appearance of the current cursor without actually making a new cursor object in the OS (and thus keeping the same handle value), but I don't think that's likely, especially since SetCursor exits immediately when the cursor hasn't changed, and I expect the API function doesn't do the graphical comparison you're trying to avoid, either. It just compares the HCursor value.