SetForegroundWindow Win32-API not always works on Windows-7

BIG NOTE

After messing with this API for the last 2 months, the solution/s below are all not stable solutions, but they work in some/most cases, depends on your environment, so keep that in mind.

 

The solution

The trick is to make windows ‘think’ that our process and the target window (hwnd) are related by attaching the threads (using AttachThreadInput API) and using an alternative API: BringWindowToTop.

 

Forcing Window/Internet Explorer to the foreground

private static void ForceForegroundWindow(IntPtr hWnd)
{
    uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), 
        IntPtr.Zero);
    uint appThread = GetCurrentThreadId();
    const uint SW_SHOW = 5;

    if (foreThread != appThread)
    {
        AttachThreadInput(foreThread, appThread, true);
        BringWindowToTop(hWnd);
        ShowWindow(hWnd, SW_SHOW);
        AttachThreadInput(foreThread, appThread, false);
    }
    else
    {
        BringWindowToTop(hWnd);
        ShowWindow(hWnd, SW_SHOW);
    }
}

A more advanced implementation of AttachedThreadInputAction pattern

The idea is to attach to the target process thread and preform an action.

public static void AttachedThreadInputAction(Action action)
{
    var foreThread = GetWindowThreadProcessId(GetForegroundWindow(), 
        IntPtr.Zero);
    var appThread = GetCurrentThreadId();
    bool threadsAttached = false;

    try
    {
        threadsAttached =
            foreThread == appThread ||
            AttachThreadInput(foreThread, appThread, true);

        if (threadsAttached) action();
        else throw new ThreadStateException("AttachThreadInput failed.");
    }
    finally
    {
        if (threadsAttached)
            AttachThreadInput(foreThread, appThread, false);
    }
}

Usage

public const uint SW_SHOW = 5;

///<summary>
/// Forces the window to foreground.
///</summary>
///hwnd”>The HWND.</param>
public static void ForceWindowToForeground(IntPtr hwnd)
{
    AttachedThreadInputAction(
        () =>
        {
            BringWindowToTop(hwnd);
            ShowWindow(hwnd, SW_SHOW);
        });
}

public static IntPtr SetFocusAttached(IntPtr hWnd)
{
    var result = new IntPtr();
    AttachedThreadInputAction(
        () =>
        {
            result = SetFocus(hWnd);
        });
    return result;
}

Importing Win32-API to do the job

[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, 
    out uint lpdwProcessId);

// When you don't want the ProcessId, use this overload and pass 
// IntPtr.Zero for the second parameter
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, 
    IntPtr ProcessId);

[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();

/// The GetForegroundWindow function returns a handle to the 
/// foreground window.
[DllImport("user32.dll")] 
public static extern IntPtr GetForegroundWindow(); 

[DllImport("user32.dll")]
public static extern bool AttachThreadInput(uint idAttach, 
    uint idAttachTo, bool fAttach); 

[DllImport("user32.dll", SetLastError = true)] 
public static extern bool BringWindowToTop(IntPtr hWnd); 

[DllImport("user32.dll", SetLastError = true)]
public static extern bool BringWindowToTop(HandleRef hWnd); 

[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);

Abstract

After an interesting research, a solution found to force a window to the top in order to simulate user key presses using SendKeys.

Problem description

We want to type-keys to simulation user key presses like: strings, enters, tabs…

We are using SendKeys API. This API require that the wanted target window will be in the foreground and the wanted control will be in focus.

Seems that since 2007, Vista added  UAC (User Account Control) and , in a nutshell, SetForegroundWindow is not working as expected.

After researching the problem, the behavior is that calling SetForegroundWindow for the first time fails (returns false).

After extensive research and readings, it seems that ‘SetForegroundWindow’ have new rules (for security reasons) and the main idea is that ‘An application can’t force another application to be in the foreground, unless it created it or related to it somehow’ (the full rules can be found here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).aspx, see ‘Rules’)

Resources

[vb2008] SetForegroundWindow not always works [Archive] – Xtreme Visual Basic Talk.

pinvoke.net: the interop wiki!

Force Window to Front (not blink in taskbar) – Microsoft: Visual FoxPro FAQ – Tek-Tips.

Bring Process to the front – CodeProject.

SetForegroundWindow  – http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).aspx

BringWindowToTop – http://msdn.microsoft.com/en-us/library/windows/desktop/ms632673(v=vs.85).aspx

VN:F [1.9.22_1171]
Rating: 8.8/10 (4 votes cast)
VN:F [1.9.22_1171]
Rating: +5 (from 5 votes)
SetForegroundWindow Win32-API not always works on Windows-7, 8.8 out of 10 based on 4 ratings
Posted in .Net, C#, Development, Win-Dev Tagged with: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
15 comments on “SetForegroundWindow Win32-API not always works on Windows-7
  1. Brilliant! This is what I’ve been searching for years… :D

    Also, I think it’s the same technique that being used by WMP12 (Windows Media Player 12) to always get its window back.

    Thanks a lot for this.

  2. Diego says:

    Thanks a lot, this solved a major problem for us !

    • ShloEmi says:

      Your welcome, glad it helps.

      BTW – Consider using the ‘Attach to target thread’ pattern presented in the solution to overcome similar problems (I’ve use it to solve other issues related to automating other processes in windows 7).

  3. ShloEmi says:

    *** IMPORTANT NOTE!!! ***
    Unfortunately, the solution is still not working on window-7.
    I hope to solve this issue, and and report a working solution in the near future.
    *************************

    • What do you mean?

      I have used it in my WPF app running on Windows 7 SP1 x64, and it’s always working so far, especially compared to using Window.Activate().

      • ShloEmi says:

        After several windows updates we encountered some problems with type-keys.

        Currently, we encounter an unstable behavior: sometimes it works and sometimes it doesn’t. I can’t even tell what are the parameters that it’s not working.
        It used to work on my development computer and one day it just doesn’t.

        We are trying to find the problem and I’ll update a solution if one will be found.

  4. ShloEmi says:

    A probable fix is found, we’re still checking it:
    var mainWindowHandle = Process.GetProcessById(processID).MainWindowHandle;
    WinApi.SwitchToThisWindow(mainWindowHandle, true);

    WinApi.SendKeys(text);

    I’ll update later on…

  5. ShloEmi says:

    Unfortunately, SwitchToThisWindow doesn’t works :-( – it’s not stable, sorry.

  6. ShloEmi says:

    After dealing with this issue for a long time (~2 months) I regret to inform that a solution was not found.

  7. Daniel says:

    After trying several things to get this problem solved, I tried following and it works:

    EventHandler showHandler = null;
    showHandler = ( sender, args ) =>
    {
    ( ( Form ) sender ).TopMost = false;
    ( ( Form ) sender ).Shown -= showHandler;
    };
    window.TopMost = true;
    window.Shown += showHandler;

    • Niku says:

      Hi Daniel,
      how did you sorted out the problem you had? can you bit elaborate this… as i have tried very hard to hold my window in front and keep a focus on it..used all the win API calls and also those you described above but finally didn’t get anything out of it.
      As win 7 passes focus to the app which is its own decision. irrespective of whether you launch a new application via Process.Start(“notepad.exe”) and try to get focus on it… but the real think is that you cannot steal focus from other application running in foreground before you launch yours.

  8. Artiom says:

    I’ve fixed that Next way:
    Application.Current.MainWindow.TopMost=false;
    Application.Current.MainWindow.TopMost=true;

    Application.Current.MainWindow.Focus();

    But sometimes the window is blinking in taskbar, but that wasn’t an issue for me

3 Pings/Trackbacks for "SetForegroundWindow Win32-API not always works on Windows-7"
  1. […] Solved: SetForegroundWindow Win32-API not always works on Windows-7 Posted on September 4, 2012 by ShloEmi — No Comments ↓ […]

Leave a Reply

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

%d bloggers like this: