In this tip, you will learn how to bypass the limitation of using ::SetForegroundWindow() function.
Introduction
This can help you to bypass limitation of using ::SetForegroundWindow()
function.
Before looking at the code, here is something from MSDN:
Quote:
The system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true:
- The process is the foreground process.
- The process was started by the foreground process.
- The process received the last input event.
- There is no foreground process.
- The foreground process is being debugged.
- The foreground is not locked (see
LockSetForegroundWindow
). - The foreground lock time-out has expired (see
SPI_GETFOREGROUNDLOCKTIMEOUT
in SystemParametersInfo
). - No menus are active.
An application cannot force a window to the foreground while the user is working with another window. Instead, Foreground
and Background
Windows will activate the window (see SetActiveWindow
) and call the function to notify the user.
A process that can set the foreground window can enable another process to set the foreground window by calling the AllowSetForegroundWindow
function. The process specified by dwProcessId
loses the ability to set the foreground window the next time the user generates input, unless the input is directed at that process, or the next time a process calls AllowSetForegroundWindow
, unless that process is specified.
The foreground process can disable calls to SetForegroundWindow
by calling the LockSetForegroundWindow
function.
The system automatically enables calls to SetForegroundWindow
if the user presses the ALT key or takes some action that causes the system itself to change the foreground window (for example, clicking a background window).
This function is provided so applications can prevent other applications from making a foreground change that can interrupt its interaction with the user.
So, there are two ways:
First, it works like Alt+TAB window switching in Windows:
void SetForegroundWindowInternal(HWND hWnd)
{
if(!::IsWindow(hWnd)) return;
BYTE keyState[256] = {0};
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);
}
}
}
And second. In this version, we are attaching the input processing mechanism of our thread to that of active thread.
void SetForegroundWindowInternal(HWND hWnd)
{
if(!::IsWindow(hWnd)) return;
DWORD lockTimeOut = 0;
HWND hCurrWnd = ::GetForegroundWindow();
DWORD dwThisTID = ::GetCurrentThreadId(),
dwCurrTID = ::GetWindowThreadProcessId(hCurrWnd,0);
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);
}
}
Have a nice day! :)
History
- 28th April, 2010: Initial version