5

首先,我知道这是一个有争议的讨论,但我希望我们能保持这种技术性。

我有一个在后台启动的应用程序,我希望它能够激活/使窗口聚焦在不同的进程中。但是,即使我要激活其窗口的进程调用了 AllowSetForegroundWindow(ASFW_ANY),调用 SetForegroundWindow 总是会失败。

原因是(IMO)启动应用程序是后台进程,并且由于它没有收到输入,因此不允许设置前台窗口。所以一切都出现在任务列表中,但没有显示出来。

所以我尝试创建一个虚拟窗口来接收立即关闭的输入,然后能够成功调用 SetForegroundWindow。但即使是我显示的虚拟窗口也显示在背景中。

但是,如果我打电话

AttachThreadInput(
    GetWindowThreadProcessId(GetForegroundWindow(), NULL),
    GetCurrentThreadId(), TRUE);

在创建虚拟窗口之前,该窗口确实是在前台创建的,然后我可以不同的进程中为不同的 HWND 调用 SetForegroundWindow 。

但是:如果我不创建虚拟窗口,尽管我使用 AttachThreadInput,但 SetForegroundWindow 仍然返回零。

我不明白为什么如果我创建一个自己的窗口(然后为其他窗口成功),为什么 AttachThreadInput hack 会成功,但如果我不先创建自己的窗口则不成功。

我的后台进程如何在不同进程中的不同窗口上调用 SetForegroundWindow而不创建虚拟窗口?

[*] 后台应用程序实际上是 gpg-agent.exe,它在请求密码时调用 pinentry.exe(我的应用程序)。pinentry.exe(作为后台进程运行)必须从另一个正在运行的应用程序请求密码,因此它必须将其窗口置于前台...

4

1 回答 1

0

文档AttachThreadInput()您提供了线索:

在不同线程中创建的窗口通常彼此独立地处理输入。即它们有自己的输入状态(焦点、活动、捕获窗口、按键状态、队列状态等),它们的输入处理与其他线程的输入处理并不同步。通过使用 AttachThreadInput 函数,一个线程可以将其输入处理机制附加到另一个线程。两个线程接收到的键盘和鼠标事件由 idAttachTo 参数指定的线程处理,直到通过第二次调用 AttachThreadInput 并为 fAttach 参数指定 FALSE 来分离线程。这也允许线程共享它们的输入状态,因此它们可以调用 SetFocus 函数将键盘焦点设置到不同线程的窗口。这也允许线程获取键状态信息。

文档告诉您调用进程需要满足SetForegroundWindow()哪些条件才能设置前景窗口:

系统限制哪些进程可以设置前台窗口。只有当下列条件之一为真时,进程才能设置前台窗口:

该进程是前台进程。
该进程由前台进程启动。
进程收到最后一个输入事件。
没有前台进程。
正在调试进程。
前台进程不是现代应用程序或开始屏幕。
前景未锁定(请参阅 LockSetForegroundWindow)。
前台锁定超时已过期(请参阅 SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。
没有菜单处于活动状态。

简单地创建一个虚拟窗口本身并不能保证您将成为前台进程。将您的窗口线程附加到当前前台窗口的线程允许您共享其输入状态,如果前台线程有权这样做,这使您有更好的机会获得设置前台窗口的权限。

于 2014-05-18T05:23:36.580 回答