0

I need my window to be on top of another window. That "other" window (application) is from different developer. I do not have source codes for it. I can only use Spy++ to get information about it.

I am using Windows 7.

I tryed several things but they did not work.

This is what I tryed so far:

1) Timer + BringWindowToTop

2) I changed Owner of my window

        IntPtr handle = User32.FindWindow("Vega Prime", "Vega Prime");

        NativeWindow win = new NativeWindow();
        win.AssignHandle(handle);

        ChildForm form = new ChildForm();
        form.Show(win);

When I am saying that it does not work I mean this:

1) at first everything looks alright: my window is on top

2) then I click on window (Vega Prime) which is below mine

3) my window disappears

4) I click on place where my window should be and it reappears (!!!!!!)

What is that? How is it possible at all?

UPDATE:

I spent some time trying to find solution to my problem. Here is what I found:

TopMost window going behind non-TopMost fullscreen window sometimes

https://social.msdn.microsoft.com/Forums/vstudio/en-US/92e66584-6cb8-4976-9531-eab3b9a129e3/mfc-window-with-wsextopmost-hidden-by-full-screen-window?forum=vcgeneral

I am pretty sure that my problem has something to do with "Full Screen Issue" at Windows 7 (sometimes, when not top most window becomes full screen it forces top most windows to become hidden). That explains described above weird behaviour, right?

Community
  • 1
  • 1
walruz
  • 1,135
  • 1
  • 13
  • 33

3 Answers3

0

I realized this example that seems to do the trick:

public partial class Form1 : Form
{
    IntPtr hWndToStayOver = User32.FindWindow("Vega Prime", "Vega Prime");
    private System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();

    public Form1()
    {
        InitializeComponent();
        this.Load += new EventHandler(this.Form1_Load);
        this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
        this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        timer1.Start(); // Routine starts now that I'm sure my Form exists
    }

    void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        timer1.Stop(); // Stop routine (my Form doesn't exist anymore)
    }

    private bool AmIAboveOtherWindow()
    {
        IntPtr tmpHwnd = User32.GetNextWindow(hWndToStayOver, User32.GetNextWindowCmd.GW_HWNDPREV);
        while (tmpHwnd != (IntPtr)0)
        {
            if (tmpHwnd == this.Handle)
                return true;

            tmpHwnd = User32.GetNextWindow(tmpHwnd, User32.GetNextWindowCmd.GW_HWNDPREV);
        }
        return false;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        timer1.Stop();
        if (!AmIAboveOtherWindow()) // Check if I am behind the target window
        {
            User32.SetWindowPos(this.Handle, hWndToStayOver, 0, 0, 0, 0, // Move my Form behind the target
                User32.SetWindowPosFlags.SWP_NOMOVE |
                User32.SetWindowPosFlags.SWP_NOSIZE |
                User32.SetWindowPosFlags.SWP_SHOWWINDOW |
                User32.SetWindowPosFlags.SWP_NOACTIVATE |
                User32.SetWindowPosFlags.SWP_ASYNCWINDOWPOS);

            User32.SetWindowPos(hWndToStayOver, this.Handle, 0, 0, 0, 0, // Move target behind my Form
                User32.SetWindowPosFlags.SWP_NOMOVE |
                User32.SetWindowPosFlags.SWP_NOSIZE |
                User32.SetWindowPosFlags.SWP_SHOWWINDOW |
                User32.SetWindowPosFlags.SWP_NOACTIVATE |
                User32.SetWindowPosFlags.SWP_ASYNCWINDOWPOS);
        }
        timer1.Start();
    }
}

User32 class

public class User32
{
    [Flags]
    public enum SetWindowPosFlags : uint
    {
        SWP_ASYNCWINDOWPOS = 0x4000,
        SWP_DEFERERASE = 0x2000,
        SWP_DRAWFRAME = 0x0020,
        SWP_FRAMECHANGED = 0x0020,
        SWP_HIDEWINDOW = 0x0080,
        SWP_NOACTIVATE = 0x0010,
        SWP_NOCOPYBITS = 0x0100,
        SWP_NOMOVE = 0x0002,
        SWP_NOOWNERZORDER = 0x0200,
        SWP_NOREDRAW = 0x0008,
        SWP_NOREPOSITION = 0x0200,
        SWP_NOSENDCHANGING = 0x0400,
        SWP_NOSIZE = 0x0001,
        SWP_NOZORDER = 0x0004,
        SWP_SHOWWINDOW = 0x0040,
    }

    public enum GetNextWindowCmd : uint
    {
        GW_HWNDNEXT = 2,
        GW_HWNDPREV = 3,
    }

    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindow")]
    public static extern IntPtr GetNextWindow(IntPtr hWnd, GetNextWindowCmd uCmd);
}

Clearly, you have to add to this code some check on the target handle: this example works only if the target window exists when the Form is loaded and if it isn't closed until the end

Matteo Umili
  • 3,412
  • 1
  • 19
  • 31
  • Thank you - I will give it a try – walruz Jul 21 '15 at 16:41
  • @walruz: this is definitely not the way to go. The solution is to set the ownership b/w 2 windows with a single windows api: SetWindowLong or SetWindowLongPtr. –  Jul 21 '15 at 17:20
  • @walruz according to your update, the requirement is that the window stays over a fullscreen window. I don't think that my solution will help in this case – Matteo Umili Jul 21 '15 at 20:42
  • @codroipo: what do you think I should do? – walruz Jul 22 '15 at 07:44
0

Make sure you set the owner of your window to the other window. That will make sure that your window is always on top of the owner. Here's how to import the appr. native functions, just change the 'Get' to 'Set' everywhere.

Then you can invoke it like this:

SetWindowLong(handle_of_owned_window, -8, handle_of_owner_window);

Hint #1: it's easy to set the ownership b/w 2 Form instances via the Form.Owner property, however you don't have access to one of them Forms.

Hint #2: in order to access the handle of a window, it needs to be shown at least once first.

Community
  • 1
  • 1
  • Correct me if I'm wrong but you don't want your window to be positioned on top of everything (e.g. a notepad). You only want to be on top of a particular window whose handle you obtain with the FindWindow api... –  Jul 21 '15 at 17:12
  • It does not matter to me. I made my window TopMost at the very begining. Still my window did disappear from view. What do you think about that "Full Screen Issue" at Windows 7??? – walruz Jul 21 '15 at 17:40
  • My opinion is that you should get rid of the code that sets the TopMost property. It's generally not a good idea to create an application that has an influence on all other running apps with a UI. Unless of course it is a requirement. There are very few apps out there that make use of TopMost, like Task Manager / Process Explorer but they both make it possible to enable / disable this behaviour. –  Jul 21 '15 at 18:10
  • Please take a look at the "trick" that I did with NativeWindow. Isn't it the same with what you are suggesting? – walruz Jul 21 '15 at 18:57
  • To verify that your "trick" does not work, use Spy++, find your window --> right-click on it--> properties --> Windows tab --> check the owner window group. Is there a valid handle there or (None)? –  Jul 21 '15 at 19:12
  • That is a great idea! Thank you! I am going to verify it tomorrow. – walruz Jul 21 '15 at 19:21
  • Any luck @walruz? Can you verify the window handle is not the one you would expect to be? –  Jul 22 '15 at 09:28
  • I did check window handle - it was there. I spent all day reading and googling. There is thing called "Full screen exclusive mode". Some call it "real" full screen. When it is active OS ignores all other windows. Games use it to achive 100% HW functionality, PowerPoint use it to avoid pop-up windows during presentations and so on. – walruz Jul 22 '15 at 09:48
  • Did you try the solution I proposed at all? –  Jul 22 '15 at 09:49
  • Most amazing part is that there is no basic cure to resolve problems like mine. – walruz Jul 22 '15 at 09:52
  • Look man, I really wanna help you, pls give my solution a try, I mean, what can you lose? And if it doesn't work, I'll keep my mouth shut! :)) –  Jul 22 '15 at 09:53
  • I cannot find SetWindowOwner function that you mentioned. Did you mean SetWindowLong? – walruz Jul 22 '15 at 09:55
  • Aye, sorry my bad. Let me try to fix that in the answer. –  Jul 22 '15 at 09:56
  • I appriciate your help very much. I am going to give it a try right now. – walruz Jul 22 '15 at 09:57
  • Also, you can use IntPtr instead of HandleRef everywhere for the sake of simplicity. –  Jul 22 '15 at 09:57
  • I tried your suggestion - it does not work. :( Spy++ showed me that Owner was properly set. Thank you very much any way. – walruz Jul 22 '15 at 10:14
0

It turned out that "other" application (which I was trying to merge with my application) is using Full-Screen Exclusive Mode. That explains why my topmost window disappeared from view and never reappeared (unless I switch off fullscreen mode with mouse click).

Details about Full-Screen Exclusive Mode are here:

https://docs.oracle.com/javase/tutorial/extra/fullscreen/exclusivemode.html

Basic idea is that Full-Screen Exclusive Mode "allows the programmer to suspend the windowing system so that drawing can be done directly to the screen". I believe that means that during Full-Screen Exclusive Mode (some experts call it "real full screen") OS ignores different windows (to save resources).

The only solution in situation like that is to configure "other" application to disable full screen mode.

It helped in my case - I studied documentation and found a place in configuration file where to set full screen mode to false.

walruz
  • 1,135
  • 1
  • 13
  • 33