Win32: Bring a Window to Top

Set a window to be topmost

Use CreateWindowEx with (extended) window style WS_EX_TOPMOST.

Disclaimer: it's about 15 years or so since I touched that stuff.

How fix window on top

You can make your window top-most by setting the WS_EX_TOPMOST extended style when you create the window, or afterwards by calling SetWindowPos with HWND_TOPMOST as the second parameter.

Note however there's no way to make your window stay on top of other top-most windows (i.e. there's no "on top of absolutely everything" flag).

Win32: Returning a minimized and hidden window to top

Could you have a look if the functions return any errors?

You could also have a look at SetForegroundWindow

How to bring other app window to 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].

Bringing Window to the Front in C# using Win32 API

SetForegroundWindow is supposed to steal focus and there are certain cases where it will fail.

The SetForegroundWindow function puts the thread that created the specified window into the foreground and activates the window. Keyboard input is directed to the window

Try capturing the focus with SetCapture prior to making the call. Also look into different ways of bringing the window to the front: SetForeGroundWindow, SetActiveWindow, even simulating a mouse click can do this.

How to bring window on top of the process created through CreateProcess

You can try to use the STARTUPINFO structure which is passed in with CreateProcess and set SW_SHOW. I'm not sure this will help bring the focus to the top though. If that doesn't work then try the following.

First off, do not use FindWindow(), it is unnecessarily unreliable since it only works via the window name and class name. Instead, from your CreateProcess() call you should read lpProcessInformation and grab the dwProcessId. Then call EnumWindows() and have your callback look something like this:

BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam ) {
DWORD dwPID;

GetWindowThreadProcessId( hwnd, &dwPID );

if( dwPID == lParam ) {
SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );

// Or just SetFocus( hwnd );
return FALSE;
}

return TRUE;
}

When calling EnumWindows() you will need to pass in the PID you grabbed earlier as the lParam like so:

EnumWindows( EnumWindowsProc, ( LPARAM )( PI -> dwProcessId ) );

How to get application window to top

Try using DllImport instead, like this:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.DLL")]
public static extern IntPtr FindWindow(string lpszClass, string lpszWindow);

Define hWnd like:

IntPtr hWnd;

In your assignment do:

hWnd = theProcess.MainWindowHandle;  // or use your theProcess.Handle

Also, that break in your if statement will not set the window to foreground if it finds it. You need to re-work that code segment to something like:

if (theprocess.ProcessName.StartsWith(name))
{
main_title = theprocess.MainWindowTitle;
hWnd = theProcess.MainWindowHandle;
}
else
hWnd = FindWindow(null, main_title);

if (hWnd != null && !hWnd.Equals(IntPtr.Zero))
{
SetForegroundWindow(hWnd);
// may want to put your break here
}

Window Class

Win32 is just a class that contains all the DllImport's described above, as I use them in multiple Win32 child classes.

public class Window : Win32
{
public IntPtr Handle;

public Window(IntPtr handle)
{
Handle = handle;
}

public bool Visible
{
get { return IsWindowVisible(Handle); }
set
{
ShowWindow(Handle, value ? ShowWindowConsts.SW_SHOW :
ShowWindowConsts.SW_HIDE);
}
}

public void Show()
{
Visible = true;
SetForegroundWindow(Handle);
/*
try { SwitchToThisWindow(Handle, false); } // this is deprecated - may throw on new window platform someday
catch { SetForegroundWindow(Handle); } //
*/
}

public void Hide() { Visible = false; }
}

The ShowWindowConsts class

namespace Win32
{
public class ShowWindowConsts
{
// Reference: http://msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx

/// <summary>
/// Minimizes a window, even if the thread that owns the window is not responding.
/// This flag should only be used when minimizing windows from a different thread.
/// </summary>
public const int SW_FORCEMINIMIZE = 11;

/// <summary>
/// Hides the window and activates another window.
/// </summary>
public const int SW_HIDE = 0;

/// <summary>
/// Maximizes the specified window.
/// </summary>
public const int SW_MAXIMIZE = 3;

/// <summary>
/// Minimizes the specified window and activates the next top-level window in the Z order.
/// </summary>
public const int SW_MINIMIZE = 6;

/// <summary>
/// Activates and displays the window.
/// If the window is minimized or maximized, the system restores it to
/// its original size and position.
/// An application should specify this flag when restoring a minimized window.
/// </summary>
public const int SW_RESTORE = 9;

/// <summary>
/// Activates the window and displays it in its current size and position.
/// </summary>
public const int SW_SHOW = 5;

/// <summary>
/// Sets the show state based on the public const long SW_ value specified in
/// the STARTUPINFO structure passed to the CreateProcess function by
/// the program that started the application.
/// </summary>
public const int SW_SHOWDEFAULT = 10;

/// <summary>
/// Activates the window and displays it as a maximized window.
/// </summary>
public const int SW_SHOWMAXIMIZED = 3;

/// <summary>
/// Activates the window and displays it as a minimized window.
/// </summary>
public const int SW_SHOWMINIMIZED = 2;

/// <summary>
/// Displays the window as a minimized window.
/// This value is similar to public const long SW_SHOWMINIMIZED,
/// except the window is not activated.
/// </summary>
public const int SW_SHOWMINNOACTIVE = 7;

/// <summary>
/// Displays the window in its current size and position.
/// This value is similar to public const long SW_SHOW, except that the window is not activated.
/// </summary>
public const int SW_SHOWNA = 8;

/// <summary>
/// Displays a window in its most recent size and position.
/// This value is similar to public const long SW_SHOWNORMAL,
/// except that the window is not activated.
/// </summary>
public const int SW_SHOWNOACTIVATE = 4;

public const int SW_SHOWNORMAL = 1;
}
}

So your code would become:

if (theprocess.ProcessName.StartsWith(name))
{
main_title = theprocess.MainWindowTitle;
hWnd = theProcess.MainWindowHandle;
}
else
hWnd = FindWindow(null, main_title);

if (hWnd != null && !hWnd.Equals(IntPtr.Zero))
{
new Window(hWnd).Show();
}

What's the correct way to bring a window to the front

Your process needs to satisfy a few conditions for it to be able to set the foreground window.

This is to prevent applications from stealing focus - which is a very bad user experience.

Imagine you're writing an email, and halfway through it your application decides now would be a good time to push a window into foreground. As you're typing suddenly the focused window would instantly change and your keypresses would now be sent to your program instead of the mail program. Not only could this cause all sorts of havoc (the keys you pressed are now sent to your program, so hotkeys might get triggered, dialogs dismissed, etc...) - but it would also be a really frustrating experience for the user (especially for less technically-inclined people).

That is the reason why SetForegroundWindow() & similar functions sometimes won't push your window to the foreground, but still report success. Your window will still flash in the task bar though, so users know that something happened in your application.



SetForegroundWindow

The exact list of conditions that need to be met for SetForegroundWindow() to work are detailed in the documentation:

The system restricts which processes can set the foreground window.

A process can set the foreground window only if one of the following conditions is true:

  • The process is the foreground process.
  • The process was started by the foreground process.
  • The process received the last input event.
  • There is no foreground process.
  • The foreground process is being debugged.
  • The foreground is not locked (see LockSetForegroundWindow).
  • The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
  • No menus are active.

An application cannot force a window to the foreground while the user is working with another window ¹. Instead, Windows flashes the taskbar button of the window to notify the user.

1 this is what prevents the mail program example detailed above from happening.

A process that fulfills these criteria can also "share" its permission to set the foreground window with another process by calling AllowSetForegroundWindow()



SetActiveWindow

SetActiveWindow() only works if the targeted window is attached to your message queue and one of your application windows is currently the foreground window.

Activates a window. The window must be attached to the calling thread's message queue.

The window will be brought into the foreground (top of Z-Order) if its application is in the foreground when the system activates the window.



BringWindowToTop

BringWindowToTop() is a convenience function for SetWindowPos(), which again has the same restrictions:

If an application is not in the foreground, and should be in the foreground, it must call the SetForegroundWindow function.

To use SetWindowPos to bring a window to the top, the process that owns the window must have SetForegroundWindow permission.



Using UI Automation

Since you mentioned that you need this functionality for an accessibility tool, here's how you could accomplish this using UI Automation:

This example uses bare-bones COM for simplicity, but if you want you can of course use e.g. wil for a more C++-like API.

#include <uiautomation.h>

bool MoveWindowToForeground(IUIAutomation* pAutomation, HWND hWnd) {
// retrieve an ui automation handle for a given window
IUIAutomationElement* element = nullptr;
HRESULT result = pAutomation->ElementFromHandle(hWnd, &element);
if (FAILED(result))
return false;

// move the window into the foreground
result = element->SetFocus();

// cleanup
element->Release();
return SUCCEEDED(result);
}

int main()
{
// initialize COM, only needs to be done once per thread
CoInitialize(nullptr);

// create the UI automation object
IUIAutomation* pAutomation = nullptr;
HRESULT result = CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, reinterpret_cast<LPVOID*>(&pAutomation));
if (FAILED(result))
return 1;

// move the given window into the foreground
HWND hWnd = FindWindowW(nullptr, L"Calculator");
MoveWindowToForeground(pAutomation, hWnd);

// cleanup
pAutomation->Release();
CoUninitialize();

return 0;
}


Related Topics



Leave a reply



Submit