【问题标题】:Understanding AttachThreadInput - detaching lose focus了解 AttachThreadInput - 分离失去焦点
【发布时间】:2013-07-26 15:17:27
【问题描述】:

我在完全理解 AttachThreadInput 时遇到了一点问题。

我知道它“连接”了 2 个线程的消息队列,这(我想做的)让我可以强制我的窗口(winforms)在前台。

我可以用这个方法做什么:

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

但是,一旦线程分离,两个窗口都会失去焦点。

如果我等待消息队列清空 (Application.DoEvents()) 并激活我的窗口(现在处于前台但未聚焦),它将重新获得焦点并保持它。

如果我在消息队列为空之前这样做,它将再次失去焦点。

所以我猜想分离的某些东西会将焦点从我的窗户上移开,但我不知道那是什么或如何防止它。

这是我首先不太明白的。

我没有得到的第二件事是,如果我没有将窗口设置为前景:

AttachThreadInput(foregroundThread, appThread, true);

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

等待消息队列清空,然后激活我的窗口(这次它不在前台,另一个窗口仍然有焦点),它实际上被激活了,即使线程不再附加。

也许对 AttachThreadInput 有更好理解的人可以回答我这两个问题。

信息:
在这种情况下,我需要转移注意力,因为我的应用程序是通过 API 调用的。调用我的另一个应用程序等待我的应用程序的反馈,并且在大多数情况下会冻结,直到它获得信息。

如果其他应用程序是全屏的,许多用户不会注意到任务栏中的闪烁,并认为其他应用程序崩溃并使用 Taskmamanger 将其杀死。由于我不一定可以控制其他应用程序,因此我不能告诉它将焦点设置到我的窗口。

如果不是绝对必要,则不会调用此方法,在这种情况下,我知道这种敌对行为是我自己和用户都想要的。

【问题讨论】:

  • 你可能会觉得thisthis 很有趣。
  • 这两个链接都告诉我我想附加线程输入有多糟糕,不是吗?或者还有什么我错过的吗?我知道这不是一个常见的练习,应该不惜一切代价阻止它,但就我而言,我实际上需要这样做。
  • 请注意,我不是这里的专家,但最近才阅读了那篇文章。话虽如此,您可能希望将代码片段的第一行与this example 中的第一行进行比较。从不经意的角度来看,他们喜欢完全相同(因此表明文章“错误”)。当然是 YMMV。
  • hm 我的应用程序和其他应用程序都没有冻结。但与本文不同的是,我不调试它,我什至没有运行 vs studio,因为调试器改变了各种行为(包括这一行为)。唯一的其他区别是 getCurrentThread 和 GetForegroundThread 的顺序,这无关紧要(已经测试过)
  • 当然有更好的方法来完成你所需要的,然后是这个可怕的黑客。包括对用户不那么敌对的方式,这样您的卸载程序就不会成为您应用程序中最常用的功能。如果你不描述你为什么需要这个,你就无法得到好的建议。

标签: c# multithreading winforms winapi


【解决方案1】:

这是我用于相同目的的一段 c# 代码。我想指出,在某些合法情况下可能需要这样做。在我们的情况下,它是 MS Word 自动化。每当用户点击我们应用程序中的工具栏按钮时,我们应该立即将 Word 窗口引起用户的注意。

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

【讨论】:

  • 有效,我只用Win32.ShowWindow(window, Win32.SW_SHOW);
  • 嗨@noseratio,我面临着类似的问题。我想知道你为什么在上面的sn-p中使用FOREGROUNDLOCKTIMEOUT
  • @IshanPandya,根据the docsSPI_GETFOREGROUNDLOCKTIMEOUT 设置系统不允许应用程序在用户输入之后的时间量,以毫秒为单位强制自己进入前台。 因为我确实想强制我的应用程序进入前台,所以我想将其设置为 0。
猜你喜欢
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
相关资源
最近更新 更多