65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (29投票s)

2010 年 4 月 28 日

CPOL

2分钟阅读

viewsIcon

185630

使用 SetForegroundWindow() 将窗口置顶

引言

这可以帮助您绕过使用 ::SetForegroundWindow() 函数的限制。

在查看代码之前,这里有一些来自 MSDN 的内容

引用

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

  • 该进程是前台进程。
  • 该进程是由前台进程启动的。
  • 该进程接收到了上次的输入事件。
  • 没有前台进程。
  • 前台进程正在被调试。
  • 前台未被锁定(请参阅 LockSetForegroundWindow)。
  • 前台锁定超时已过期(请参阅 SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。
  • 没有活动的菜单。

当用户正在使用另一个窗口时,应用程序无法强制将窗口置于前台。相反,ForegroundBackground 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 日:初始版本
© . All rights reserved.