35

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

7 Answers7

30

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);
bowman han
  • 1,097
  • 15
  • 25
  • I have been looking for this magic song-and-dance for quite some time now. It works perfectly for me. – ulatekh Aug 02 '16 at 22:49
  • 2
    I still can`t understand what it does,but just works – bowman han Aug 03 '16 at 03:01
  • Wish I could say the same. Didn't work for me. Dialog box gets focus but another dialog box remains in front of it. – Brian Reinhold Nov 27 '16 at 23:53
  • Not work for me when I want to bring a minimize windows to the top in win7. It just do not bring the minimize windows to the top. It can bring the windows to the top if the windows is not minimize. The SetFocus api return error code 0x57 "The parameter is incorrect." in my case on win7. I do not know why this code ignore all windows api error. – bronze man Dec 05 '17 at 02:24
  • without source code of windows api, it`s hard to say – bowman han Dec 08 '17 at 16:54
  • The reason (i think) it doesn't work for bowman is the code above doesn't adjust window state. something like ::ShowWindow(hWnd, SW_RESTORE); should help. – Alan Baljeu Feb 25 '20 at 19:04
  • I realized my code have some error, I corrected it, you guys may have a try – bowman han Feb 26 '20 at 09:55
14

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.

Nuno
  • 1,910
  • 2
  • 21
  • 33
  • I might be a bit late, but you have to call `::SetForegroundWindow` before showing the window (make sure update the window aswell). – Cedric Nov 22 '17 at 17:48
12

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.
user4035
  • 22,508
  • 11
  • 59
  • 94
bronze man
  • 1,470
  • 2
  • 15
  • 28
  • 1
    you have no idea how much this helped me. Everything is bug free and fully works. The window is activated, re-drawn, without moving it or changing sizes. if it was maximized it will be maximized. only issue with this is if the window was maximized or full screen it wouldn't restore to it's previous state – joseph lake Jun 23 '23 at 20:22
  • 1
    edit this doesn't work for if this is called from the same process tested with GetConsoleWindow() which returns HWND of the current console window from your current process. – joseph lake Jun 24 '23 at 23:45
8

SwitchToThisWindow works best for me.

scottm
  • 27,829
  • 22
  • 107
  • 159
  • 20
    MSDN: this function is deprecated and not intended for general use. It is recommended that you do not use it in new programs because it might be altered or unavailable in subsequent versions of Windows. – Shay Erlichmen May 27 '09 at 18:18
4

Have you tried SetActiveWindow()?

rtn
  • 127,556
  • 20
  • 111
  • 121
0

This will restore an app if minimized and bring it to the front:

ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);
-6

//work great!

Var
 WndHandle:HWND;

begin
 WndHandle :=FindWindowEx(0,0,nil,'Calculator');
 PostMessage(WndHandle,WM_SHOWWINDOW,SW_RESTORE,0);
 SetForegroundWindow(WndHandle);
end;