How do I get back the OLD SetForegroundWindow behaviour?

Method 1 (not functional on Windows 2000+)

For Windows 98/IE5, Microsoft changed the behaviour of SetForegroundWindow so as to stop you grabbing the focus. Normally, this would be entirely laudable (most applications don't REALLY need to grab focus, they just do it anyway), but there are some special kinds of applications which really need to be able to grab focus. Fortunately, there is a workaround. This involves using the lock timeout feature that also arrived with the new UI.

void CMyDlg::ActualSetForegroundWindow (HWND hWnd) { DWORD dwTimeoutMS; // Get the current lock timeout. SystemParametersInfo (0x2000, 0, &dwTimeoutMS, 0); // Set the lock timeout to zero SystemParametersInfo (0x2001, 0, 0, 0); // Perform the SetForegroundWindow ::SetForegroundWindow (hWnd); // Set the timeout back SystemParametersInfo (0x2001, 0, (LPVOID)dwTimeoutMS, 0); }

If you have the latest header files, you'll see the following definitions:

#define SPI_GETFOREGROUNDLOCKTIMEOUT        0x2000
#define SPI_SETFOREGROUNDLOCKTIMEOUT        0x2001

I just use the literal values here to ensure it compiles for everybody.

Method 2

Here's a method which uses a different tack. Since Windows permits the foreground process to set the foreground window without any restrictions, this code attaches to the foreground thread's input queue so as to "look" like it, then calls SetForegroundWindow as before. Note : this MAY work on Win2k, it seems to depend upon the patch level and IE version you have installed. With OOB win2k code it seems to work. It's also been tested on Windows XPsp1 and found to work.

BOOL  W2K_SetForegroundWindow (HWND hWndToForce)
{
   HWND   hCurrWnd;
   int    iMyTID;
   int    iCurrTID;
   BOOL bRetVal;
   DWORD dwPid;

   hCurrWnd = GetForegroundWindow ();
   iMyTID = GetCurrentThreadId ();
   iCurrTID = GetWindowThreadProcessId (hCurrWnd,&dwPid);

   // Connect to the current process.
   AttachThreadInput (iMyTID, iCurrTID, TRUE);

   // Now we look like the foreground process, we can set the
   // foreground window.
   bRetVal = SetForegroundWindow (hWndToForce);

   if (!bRetVal)
   {
      char   szBuffer [60];
      wsprintf (szBuffer, "Error %u from SetForegroundWindow\n",
                GetLastError());
      OutputDebugString (szBuffer);
   }
   // Now detach.
   AttachThreadInput (iMyTID, iCurrTID, FALSE);
   return bRetVal;
}

Do I feel guilty about providing workarounds for the new UI standard? NO. Microsoft feel perfectly OK about ignoring this rule when it suits them (e.g. Internet Explorer 5, Windows CE Services), so when they start obeying this supposed rule, so will I.

Download