Why don’t Focus() and SetForegroundWindow() work?

Once upon a time Microsoft decided these functions would no longer bring things to the foreground on Windows (about the time of Windows ME). Instead, these functions would make the taskbar button of the program or window flash incessantly.

This is all well and good, and I’m sure there were good intentions behind it, but quite frankly, it’s annoying when your app is supposed to come to the foreground and it doesn’t.

I found this problem while developing in .NET, so most of my code will be heavy on that side, but should easily be convertable to non-.NET (in fact, I’ll be showing you the exact DLL’s the functions are in, so you can just write language specific binding as an exercise Wink ).

The Managed C++ Code that doesn’t work:

((System.Windows.Forms.Form *) myForm)->Focus()

The C# Code that doesn’t work:

myForm.Focus()

This just flashes myForm’s taskbar button (although this behavior can be changed by editing the registry, this is the default behavior). What we want to do is force our form to the foreground. Initially, one would suspect that a lower level call to SetForegroundWindow() would do this, but it does not. It’s result is the same. Instead, we have to temporarily modify the system’s parameter that defines the behavior we don’t like.

In Managed C++, we can do this:

::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::ShowWindowAsync((HWND) window->Handle.ToPointer(), WS_SHOWNORMAL);
::SetForegroundWindow((HWND) window->Handle.ToPointer());
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 200000, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);

In C# we need to define:

[DllImport("user32.dll", EntryPoint="SystemParametersInfo")]
public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni);

[DllImport("user32.dll", EntryPoint="SetForegroundWindow")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
      
[DllImport("User32.dll", EntryPoint="ShowWindowAsync")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
private const int WS_SHOWNORMAL = 1;

and later use:

SystemParametersInfo( (uint) 0x2001, 0, 0, 0x0002 | 0x0001);
ShowWindowAsync(window.Handle, WS_SHOWNORMAL);
SetForegroundWindow(window.Handle);
SystemParametersInfo( (uint) 0x2001, 200000, 200000, 0x0002 | 0x0001);

This all seems like a bunch of arcanum, but it’s fairly simply explained.

The first call to SystemParametersInfo tells Windows that we don’t want to flash the taskbar button, we want to bring our window to the foreground instead.

The call to ShowWindowAsync brings the window out of minimized state, if necessary.

The call to SetForegroundWindow will now actually bring our window to the foreground.

The second call to SystemParametersInfo tells Windows that we want to go back to the default, which is flashing the taskbar button.

If you notice, in the C# code, we have to tell C# how to find these functions. All three of these functions are contained in the User32.DLL file. The SystemParametersInfo() function expects all unsigned integers, so the marshalling here is no problem. The ShowWindowAsync() and the SetForegroundWindow() functions both want an HWND as their first argument, which, when it comes down to it, is a pointer — which we can just marshall as an IntPtr (which happens to be the type for the Form.Handle property). ShowWindowAsync() expects an integer value representing a particular command to perform on the form we gave it. We simply define the only one we care about WS_SHOWNORMAL (value of 1); this value instructs ShowWindowAsync() to show our form, well, ‘normally’.

A way to improve the above code would be to store the current value of the system parameter and write it back in. This is left as an exercise.

Comments

Leave a Reply

You must be logged in to post a comment.