我正在使用PInvoke在.NET中使用SetForegroundWindow API。
当我在Visual Studio调试时使用该API时,它完美地工作。但是,在应用程序通常运行时,它并不总是起作用。
我在调用SetForegroundWindow之前放置了一些日志,并确认API被调用,但有时不起作用。我也看到了几篇关于这个问题的帖子,但我想知道为什么会失败。
帖子的链接如下:
我正在使用PInvoke在.NET中使用SetForegroundWindow API。
当我在Visual Studio调试时使用该API时,它完美地工作。但是,在应用程序通常运行时,它并不总是起作用。
我在调用SetForegroundWindow之前放置了一些日志,并确认API被调用,但有时不起作用。我也看到了几篇关于这个问题的帖子,但我想知道为什么会失败。
帖子的链接如下:
SetForegroundWindow
文档提供了对你面临问题的全面解释。实际上SetForegroundWindow
设计所面临的问题是它可以用于窃取焦点。焦点是用户应该控制的东西。更改焦点的应用程序可能会引起麻烦。因此,SetForegroundWindow
尝试防止焦点窃取者。
文档说:
系统限制哪些进程可以设置前景窗口。只有满足以下条件之一的情况下,进程才能设置前景窗口:
- 进程是前台进程。
- 该进程是由前台进程启动的。
- 该进程接收到最后的输入事件。
- 没有前台进程。
- 该进程正在被调试。
- 前台进程不是Modern应用程序或开始屏幕。
- 前台没有被锁定(参见LockSetForegroundWindow)。
- 前台锁超时已经过期(参见SystemParametersInfo中的SPI_GETFOREGROUNDLOCKTIMEOUT)。
- 没有处于激活状态的菜单。
应用程序不能在用户使用其他窗口时强制将一个窗口置于前景。相反,Windows会闪烁任务栏按钮以通知用户。
你几乎肯定违反了这些标准。请注意,正在调试的进程始终被授予设置前景窗口的权限。这就是为什么在调试时看不到问题的原因。但是,在调试器外部,如果你的进程不是前台进程,则对SetForegroundWindow
的调用将失败。这都是故意设计的。你应该尝试设计一种不需要在进程不是前台进程时尝试调用SetForegroundWindow
的方案。
AttachThreadInput
。这会带来痛苦。 - David Heffernanprivate const uint WS_MINIMIZE = 0x20000000;
private const uint SW_SHOW = 0x05;
private const uint SW_MINIMIZE = 0x06;
private const uint SW_RESTORE = 0x09;
public static void FocusWindow(IntPtr focusOnWindowHandle)
{
int style = GetWindowLong(focusOnWindowHandle, GWL_STYLE);
// Minimize and restore to be able to make it active.
if ((style & WS_MINIMIZE) == WS_MINIMIZE)
{
ShowWindow(focusOnWindowHandle, SW_RESTORE);
}
uint currentlyFocusedWindowProcessId = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
if (currentlyFocusedWindowProcessId != appThread)
{
AttachThreadInput(currentlyFocusedWindowProcessId, appThread, true);
BringWindowToTop(focusOnWindowHandle);
ShowWindow(focusOnWindowHandle, SW_SHOW);
AttachThreadInput(currentlyFocusedWindowProcessId, appThread, false);
}
else
{
BringWindowToTop(focusOnWindowHandle);
ShowWindow(focusOnWindowHandle, SW_SHOW);
}
}
David是正确的,他引导我走向了正确的方向。我遵循了代码项目文章中所说的: “如果用户按下ALT键或执行某些操作导致系统自身更改前景窗口,则系统会自动启用对SetForegroundWindow的调用”
SetForegroundWindow
时,你的应用程序是前台进程吗?你认为是什么让你觉得其他应用程序正在调用 LockSetForegroundWindow
? - David HeffernanSetForegroundWindow
会有任何效果。IE肯定不需要调用LockSetForegroundWindow
,如果它这样做了,我会感到惊讶。它所需要做的就是成为前台进程,其他进程就无法更改前台进程。 - David Heffernan