有时候我们调用 SetForegroundWindow 想将某个窗口带到前台并且激活时,该窗口只是在任务栏上闪动(FlashWindow),并未能带到前台来。
研究了一下,发现是否能够成功,和 SetForegroundWindow 所在线程所附加的输入上下文有关(可以调用 AttachThreadInput 修改)。
目前以下 3 种方法均可以将任意窗口带到前台来。
-
SwitchToThisWindow API
第二个参数含义:TRUE:如果窗口被极小化了,则恢复
微软说该函数将被废弃,见:This function is not intended for general use. It may be altered or unavailable in subsequent versions of Windows。
但是根据经验可知,微软说废弃的,不知道到猴年马月才会真的从系统 API 中去除。
该方法使用最简单。 -
SetForegroundWindow & AttachThreadInput API
-
BringWindowToTop & AttachThreadInput API
注意
被 AttachThreadInput 的进程,如果是具有管理员权限的进程,则调用 AttachThreadInput 的进程也必须要有管理员权限,否则会失败,GetLastError 返回 5(拒绝访问)。
具体代码(包含以上 3 种方法):
#include <iostream>
#include <windows.h>
// SwitchToThisWindow 方法
void ActiveAnyWindow_SwitchToThisWindow(HWND hWnd)
{
// 第二个参数需要传 TRUE:这样的话,如果窗口被极小化了,可以恢复。
SwitchToThisWindow(hWnd, TRUE);
}
// SetForegroundWindow 方法
void ActiveAnyWindow_SetForegroundWindow(HWND hWnd)
{
const HWND hForeWnd = ::GetForegroundWindow();
::AttachThreadInput(::GetWindowThreadProcessId(hForeWnd, nullptr), ::GetCurrentThreadId(), TRUE);
if (!::SetForegroundWindow(hWnd))
{
std::cout << "SetForegroundWindow GLE=%d", ::GetLastError();
}
else
{
std::cout << "SetForegroundWindow OK";
}
AttachThreadInput(::GetWindowThreadProcessId(hForeWnd, nullptr), ::GetCurrentThreadId(), FALSE);
}
// BringWindowToTop 方法
void ActiveAnyWindow_BringWindowToTop(HWND hWnd)
{
const HWND hForeWnd = ::GetForegroundWindow();
::AttachThreadInput(::GetWindowThreadProcessId(hForeWnd, nullptr), ::GetCurrentThreadId(), TRUE);
if (!::BringWindowToTop(hWnd))
{
std::cout << "BringWindowToTop GLE=%d", ::GetLastError();
}
else
{
std::cout << "BringWindowToTop OK";
}
AttachThreadInput(::GetWindowThreadProcessId(hForeWnd, nullptr), ::GetCurrentThreadId(), FALSE);
}
int main()
{
// 测试前,先要手动打开系统记事本
::Sleep(3000);
ActiveAnyWindow_BringWindowToTop(::FindWindow(L"Notepad", nullptr));
}