SetWindowPos不会将应用程序放在首位

时间:2015-09-24 10:40:15

标签: c# bringtofront

我对SetWindowPos函数有一个奇怪的问题。此功能用于通过以下代码将应用程序置于顶部:

                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");

在大多数情况下,我能够从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

但有时我得到以下内容:

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

在这种情况下,SetWindowPos()返回成功,但应用程序没有达到顶峰。

这个问题太难重现,我无法轻易测试。

有谁知道WM_WINDOWPOSCHANGED缺少什么? 我该如何解决这个问题?

提前致谢!

1 个答案:

答案 0 :(得分:0)

让我把任何程序放在前面的最有效的方法是:

  1. P / Invoke - AttachThreadInput
  2. P / Invoke - BringWindowToTop
  3. P / Invoke - 带参数SW_SHOW的ShowWindow
  4. 它每次都适用于我,它从我尝试的任何应用程序中窃取焦点。 就像全屏显示Citrix或远程桌面一样,我的程序就在前台。

    诀窍是制造窗户"思考"我们的进程和目标窗口(hwnd)通过附加线程(使用AttachThreadInput API)和使用替代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);
        }
    }
    

    用法:

    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);
            });
    }