0

I have a strange problem with SetWindowPos function. This function is used to bring app on top with the following code:

                if (!SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, NO_FOCUS_FLAGS))
                    Log.LogError("SetWindowPos HWND_TOPMOST returned false");

                if (!SetWindowPos(this.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, NO_FOCUS_FLAGS))
                    Log.LogError("SetWindowPos HWND_NOTOPMOST returned false");

And in most cases I am able to see the normal events stack from Windows:

WndProc(): m - msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x21016 wparam=0x0 lparam=0x20d688 result=0x0
WndProc(): m - msg=0x14 (WM_ERASEBKGND) hwnd=0x21016 wparam=0xffffffffc60128f1 lparam=0x0 result=0x0
WndProc(): m - msg=0x135 (WM_CTLCOLORBTN) hwnd=0x21016 wparam=0xffffffff950128ae lparam=0x40f2e result=0x0
WndProc(): m - msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x21016 wparam=0x0 lparam=0x20d688 result=0x0
WndProc(): m - msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x21016 wparam=0x0 lparam=0x20d688 result=0x0
WndProc(): m - msg=0x135 (WM_CTLCOLORBTN) hwnd=0x21016 wparam=0xffffffffc60128f1 lparam=0x40f2e result=0x0
WndProc(): m - msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x21016 wparam=0x0 lparam=0x20d688 result=0x0

However sometimes I got the following:

WndProc(): m - msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x104f4 wparam=0x0 lparam=0x3ad6cc result=0x0
WndProc(): m - msg=0x14 (WM_ERASEBKGND) hwnd=0x104f4 wparam=0x26012ce9 lparam=0x0 result=0x0
WndProc(): m - msg=0x135 (WM_CTLCOLORBTN) hwnd=0x104f4 wparam=0x90127a1 lparam=0x105de result=0x0
WndProc(): m - msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x104f4 wparam=0x0 lparam=0x3ad6cc result=0x0

In this case the SetWindowPos() returned success, but application was not bring to top.

This issue is too hard to reproduce and I can't test it so easily.

Does anyone know what means missing of WM_WINDOWPOSCHANGED? How can I address this issue?

Thanks in advance!

  • I don't know why this happens but just wanted to point out that your analysis is slightly off: You do appear to have matching `WM_WINDOWPOSCHANGING` / `WM_WINDOWPOSCHANGED` messages in both traces you show here. – 500 - Internal Server Error Sep 24 '15 at 10:50
  • Are you trying to bring a window from your own process to the front, or another process? Does your process currently have the focus? You can't send a window to the front unless your process is at the front. You can't steal the focus. You can give the focus to somebody else but only if you have it. – Ben Sep 24 '15 at 11:10
  • Hi Ben, process has not focus at that moment. I am trying to bring my own process to front. Just to highlight, issue is very intermittent and in most cases all is working fine. – Alex Simatov Sep 24 '15 at 11:24
  • If you want to steal the foreground then you need a bigger weapon. A very ugly one, and users absolutely hate it, but it is [readily available](https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.interaction.appactivate%28v=vs.110%29.aspx) in .NET in everybody's favorite namespace. – Hans Passant Sep 24 '15 at 12:02

1 Answers1

0

The most effective method for me to bring any program in front is a combination of:

  1. P/Invoke - AttachThreadInput
  2. P/Invoke - BringWindowToTop
  3. P/Invoke - ShowWindow with parameter SW_SHOW

It works every time for me, and it steals focus from any application I have tried. Like have a Citrix or Remote Desktop in full screen, my program get in the foreground.

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.

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);
        });
}
rdyhalt
  • 96
  • 2
  • 8