tags:

views:

650

answers:

5

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?

A: 

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.

kdevine
A: 

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.

snowcrash09
That does it the once (but then it does it the once without it anyway). Clicking on IE brings it in front of my window :(
Mat
A: 

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.

Matthew Xavier
Mat doesn't own the parent window, so he can't change "A"'s winproc. However, maybe some type of hook of the parent would work?
Aardvark
Actually, he says he owns A and wants to make it seem a child of B, which is not his (Internet Explorer). I think that A will receive notice that A's z-order is changing if B is moved in front.
Matthew Xavier
+2  A: 

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.

Slacker
+1  A: 

Wouldn't creating an ownership relationship do the trick?

SetWindowLong(hwndOwner, GWL_HWNDPARENT, hwndChild)

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.

Mo Flanagan