0

我对 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 是什么意思?我该如何解决这个问题?

提前致谢!

4

1 回答 1

0

对我来说,将任何程序放在前面的最有效方法是以下组合:

  1. P/Invoke - AttachThreadInput
  2. P/Invoke - BringWindowToTop
  3. P/Invoke - 带有参数 SW_SHOW 的 ShowWindow

它每次都对我有用,它会从我尝试过的任何应用程序中窃取焦点。就像全屏使用 Citrix 或远程桌面一样,我的程序处于前台。

诀窍是通过附加线程(使用 AttachThreadInput API)和使用替代 API:BringWindowToTop,让窗口“认为”我们的进程和目标窗口 (hwnd) 是相关的。

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);
        });
}
于 2015-09-24T13:04:46.250 回答