如何使用 SetForegroundWindow() 将窗口置顶






4.91/5 (29投票s)
使用 SetForegroundWindow() 将窗口置顶
引言
这可以帮助您绕过使用 ::SetForegroundWindow()
函数的限制。
在查看代码之前,这里有一些来自 MSDN 的内容
引用系统限制哪些进程可以设置前台窗口。只有满足以下条件之一时,进程才能设置前台窗口:
- 该进程是前台进程。
- 该进程是由前台进程启动的。
- 该进程接收到了上次的输入事件。
- 没有前台进程。
- 前台进程正在被调试。
- 前台未被锁定(请参阅
LockSetForegroundWindow
)。- 前台锁定超时已过期(请参阅
SystemParametersInfo
中的SPI_GETFOREGROUNDLOCKTIMEOUT
)。- 没有活动的菜单。
当用户正在使用另一个窗口时,应用程序无法强制将窗口置于前台。相反,
Foreground
和Background
Windows 将激活窗口(请参阅SetActiveWindow
)并调用函数以通知用户。可以设置前台窗口的进程可以通过调用
AllowSetForegroundWindow
函数来启用另一个进程设置前台窗口。由dwProcessId
指定的进程在用户生成输入时将失去设置前台窗口的能力,除非该输入是定向到该进程的,或者在另一个进程调用AllowSetForegroundWindow
时,除非该进程被指定。前台进程可以通过调用
LockSetForegroundWindow
函数来禁用对SetForegroundWindow
的调用。
如果用户按下 ALT 键或执行导致系统本身更改前台窗口的操作(例如,单击后台窗口),系统会自动启用对 SetForegroundWindow
的调用。
提供此函数是为了让应用程序可以防止其他应用程序进行可能中断其与用户交互的前台更改。
所以,有两种方法
首先,它的工作方式类似于 Windows 中的 Alt+TAB 窗口切换
void SetForegroundWindowInternal(HWND hWnd)
{
if(!::IsWindow(hWnd)) return;
BYTE keyState[256] = {0};
//to unlock SetForegroundWindow we need to imitate Alt pressing
if(::GetKeyboardState((LPBYTE)&keyState))
{
if(!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
}
}
::SetForegroundWindow(hWnd);
if(::GetKeyboardState((LPBYTE)&keyState))
{
if(!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
}
其次,在这个版本中,我们将我们线程的输入处理机制附加到活动线程的输入处理机制上。
void SetForegroundWindowInternal(HWND hWnd)
{
if(!::IsWindow(hWnd)) return;
//relation time of SetForegroundWindow lock
DWORD lockTimeOut = 0;
HWND hCurrWnd = ::GetForegroundWindow();
DWORD dwThisTID = ::GetCurrentThreadId(),
dwCurrTID = ::GetWindowThreadProcessId(hCurrWnd,0);
//we need to bypass some limitations from Microsoft :)
if(dwThisTID != dwCurrTID)
{
::AttachThreadInput(dwThisTID, dwCurrTID, TRUE);
::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,0,&lockTimeOut,0);
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,0,SPIF_SENDWININICHANGE |
SPIF_UPDATEINIFILE);
::AllowSetForegroundWindow(ASFW_ANY);
}
::SetForegroundWindow(hWnd);
if(dwThisTID != dwCurrTID)
{
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,
(PVOID)lockTimeOut,SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::AttachThreadInput(dwThisTID, dwCurrTID, FALSE);
}
}
祝您愉快!:)
历史
- 2010 年 4 月 28 日:初始版本