11

i got a little problem fully understanding AttachThreadInput.

I know it's "connecting" the message queue of 2 threads, which (what i want to do) allows me for example to force my window (winforms) in foreground.

Which I can do with this method:

private void SetForegroundWindowEx(IntPtr hWnd)
{
    uint SW_SHOW = 5;
    uint appThread = GetCurrentThreadId();     
    uint foregroundThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);         

    if (foregroundThread != appThread)
    {
        AttachThreadInput(foregroundThread, appThread, true);

        BringWindowToTop(hWnd);
        ShowWindow(hWnd, SW_SHOW);       
        AttachThreadInput(foregroundThread, appThread, false);

    }
    else
    {
        BringWindowToTop(hWnd);
        ShowWindow(hWnd, SW_SHOW);
    }
}

However both of the windows lose focus as soon as the threads detach.

If I wait for the message queue to empty (Application.DoEvents()) and activate my window (which is now in foreground but not focused) it will regain the focus and keep it.

If I do it before the message queue is empty it will lose focus again.

So I would guess something of the detaching takes the focus from my windows but i have no idea what that is or how to prevent it.

This is the first thing I do not quite understand.

The second thing I do not get is, if I do not set my window to foreground:

AttachThreadInput(foregroundThread, appThread, true);

AttachThreadInput(foregroundThread, appThread, false);
Application.DoEvents();
this.Activate();

wait for the message queue to empty, and activate my window (this time it is not in foreground and the other window still has the focus), it actually gets activated, even though the threads are not attached anymore.

perhaps someone with a better understanding of AttachThreadInput can answer me these 2 questions.

INFO:
I need to steal the focus in this case, because my app gets called via an API. The other app that calls mine, waits for feedback from my app and in most times freezes until it gets the info.

In case the other app is Fullscreen many user do not notice the blinking in the taskbar and think the other app crashed and kill it with the Taskmamanger. Since i do not necessarily have control over the other app, i cannot tell it to set the focus to my window.

This method won't get called if it is not absolutelly necessary, in this case this behavior, which is hostile, i know that, is as well wanted by myself as by the user.

Visions
  • 919
  • 1
  • 7
  • 17
  • 1
    You might find [this](http://blogs.msdn.com/b/oldnewthing/archive/2013/06/19/10426841.aspx) and [this](http://blogs.msdn.com/b/oldnewthing/archive/2008/08/01/8795860.aspx) quite interesting. – Christian.K Jul 26 '13 at 11:17
  • well both links are telling me how bad i am for wanting to attach thread input, aren't they? Or is there something else i missed?. I know this is not a common exercise and it should be prevented at nearly all costs, but in my case i actually need to do it. – Visions Jul 26 '13 at 11:22
  • Mind you I'm no expert here, but just recently read over that one article. Having that said, you might want to compare the first lines of your code fragment with the first lines in [this example](http://blogs.msdn.com/b/oldnewthing/archive/2013/06/19/10426841.aspx). From a casual view they like quite identical (and thus stating the article "wrong"). YMMV of course. – Christian.K Jul 26 '13 at 11:27
  • hm neither does my application freeze nor the other one. But unlike in this article i do not debug it, i don't even have vs studio running, since the debugger changed all kinds of behaviors (this one included). The only other differences are the order of getCurrentThread and GetForegroundThread, which should not matter (already tested) – Visions Jul 26 '13 at 11:33
  • 1
    Surely there are better ways to accomplish what you need then this awful hack. Including ways that are a lot less hostile to the user so your uninstaller doesn't get to be the most often used feature of your app. You can't get good advice if you don't describe why you need this. – Hans Passant Jul 26 '13 at 12:19
  • added info why i need it this way – Visions Jul 26 '13 at 12:26
  • if you want to finish a job in the background without getting UI freeze you can put the job in a thread with delegate function to update the UI. – Mohammad abumazen Jul 30 '13 at 07:38

1 Answers1

12

Here's a piece of c# code I use for the same purpose. I'd like to note there are legitimate cases when this may be required. In our situation, it was MS Word automation. Whenever user clicks a toolbar button inside our app, we should immediately bring the Word window up to the user's attention.

public static void ForceWindowIntoForeground(IntPtr window)
{
    uint currentThread = Win32.GetCurrentThreadId();

    IntPtr activeWindow = Win32.GetForegroundWindow();
    uint activeProcess;
    uint activeThread = Win32.GetWindowThreadProcessId(activeWindow, out activeProcess);

    uint windowProcess;
    uint windowThread = Win32.GetWindowThreadProcessId(window, out windowProcess);

    if (currentThread != activeThread)
        Win32.AttachThreadInput(currentThread, activeThread, true);
    if (windowThread != currentThread)
        Win32.AttachThreadInput(windowThread, currentThread, true);

    uint oldTimeout = 0, newTimeout = 0;
    Win32.SystemParametersInfo(Win32.SPI_GETFOREGROUNDLOCKTIMEOUT, 0, ref oldTimeout, 0);
    Win32.SystemParametersInfo(Win32.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref newTimeout, 0);
    Win32.LockSetForegroundWindow(LSFW_UNLOCK);
    Win32.AllowSetForegroundWindow(Win32.ASFW_ANY);

    Win32.SetForegroundWindow(window);
    Win32.ShowWindow(window, Win32.SW_RESTORE);

    Win32.SystemParametersInfo(Win32.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref oldTimeout, 0);

    if (currentThread != activeThread)
        Win32.AttachThreadInput(currentThread, activeThread, false);
    if (windowThread != currentThread)
        Win32.AttachThreadInput(windowThread, currentThread, false);
}
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 1
    It works, I just use `Win32.ShowWindow(window, Win32.SW_SHOW);` – xmedeko Feb 14 '19 at 20:11
  • Hi @noseratio, I am facing similar issue. And I would like to know exactly why have you used the `FOREGROUNDLOCKTIMEOUT` in the above snippet? – Ishan Pandya Jun 21 '19 at 10:33
  • @IshanPandya, according to [the docs](https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-systemparametersinfoa), `SPI_GETFOREGROUNDLOCKTIMEOUT` *sets the amount of time following user input, in milliseconds, during which the system **does not allow** applications to force themselves into the foreground.* Because I do want to force my application into foreground, I want to set this to 0. – noseratio Jun 24 '19 at 22:25