6

If I'm enumerating windows in Application.Current.Windows, how can I tell, for any two windows, which one is "closer" (i.e. has greater z-index)?

Or, to say the same in other words, how can I sort those windows by z-index?

Fyodor Soikin
  • 78,590
  • 9
  • 125
  • 172

2 Answers2

9

You cannot get a Window's Z Order information from WPF so you must resort to Win32.

Something like this ought to do the trick:

var topToBottom = SortWindowsTopToBottom(Application.Current.Windows.OfType<Window>());
...

public IEnumerable<Window> SortWindowsTopToBottom(IEnumerable<Window> unsorted)
{
  var byHandle = unsorted.ToDictionary(win =>
    ((HwndSource)PresentationSource.FromVisual(win)).Handle);

  for(IntPtr hWnd = GetTopWindow(IntPtr.Zero); hWnd!=IntPtr.Zero; hWnd = GetWindow(hWnd, GW_HWNDNEXT)
    if(byHandle.ContainsKey(hWnd))
      yield return byHandle[hWnd];
}

const uint GW_HWNDNEXT = 2;
[DllImport("User32")] static extern IntPtr GetTopWindow(IntPtr hWnd);
[DllImport("User32")] static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);

The way this works is:

  1. It uses a dictionary to index the given windows by window handle, using the fact that in the Windows implementation of WPF, Window's PresentationSource is always HwndSource.
  2. It uses Win32 to scan all unparented windows top to bottom to find the proper order.
jchristin
  • 7,352
  • 2
  • 15
  • 18
Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • And yes, sorry, this does require unmanaged code permission ("full trust"). – Ray Burns Aug 13 '10 at 04:55
  • I'll accept this nevertheless, as it's the only answer so far. – Fyodor Soikin Aug 13 '10 at 14:49
  • Could you please take a look at my latest question? I should really like to see your angle on the problem. http://stackoverflow.com/questions/3642763/static-verification-of-bindings – Fyodor Soikin Sep 04 '10 at 22:56
  • 1
    I just wanted to add that this explanation might not be entirely accurate. pInvoke.net points out that GetNextWindow is a macro, and we should instead call GetWindow http://www.pinvoke.net/default.aspx/user32/GetNextWindow.html http://www.pinvoke.net/default.aspx/user32/GetWindow.html When I attempted to implement the above code in my .NET 4.0 WPF application it threw an exception when trying to call GetNextWindow stating it's not an available member, easily fixed by updating the method to GetWindow as defined by pInvoke.net However the rest of the code works perfectly. – SomeInternetGuy Aug 22 '14 at 12:30
-1

Ah this was a really fun one:

[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();

public static Window ActiveWindow
{
    get
    {
        return HwndSource.FromHwnd(GetActiveWindow()).RootVisual as Window;
    }
}

It will give you the active window in your app (which is usually the foremost).

Carlo
  • 25,602
  • 32
  • 128
  • 176