3

This one has me puzzled, and I am starting to believe it's a bug in either the core winapi, or possibly in WPF. In case nobody here knows a possible cause for the problem I will file a bug report at Microsoft Connect.

The problem presents itself once I call Window.Show(), but the root cause might lie in a different place, including prior calls to user32.dll. Once I call Show() on my window, my window does show up, but another window pops up on the taskbar but doesn't become visible. Moreover, clicking it does not make that window visible.

The window I am trying to show has the following properties set, which seem to be required to cause this weird behavior. Changing any of them 'fixes' this issue.

WindowStyle="None"
WindowState="Maximized"
ShowInTaskbar="False"

I am creating a virtual desktop manager (VDM), hence I hide/show windows through user32.dll. If I don't hide any windows prior to showing my desired window, the problem doesn't present itself either. The entire code of the VDM is available on github. The specific user32 calls occur in a wrapper which can also be found on github.

// Hide windows.
var hideWindows = _windows
    .Select( w => new RepositionWindowInfo( w.Info ) { Visible = false } );
WindowManager.RepositionWindows( hideWindows.ToList() );

The RepositionWindows method is a bit long to post here, but you can see it in its entirety on github. It uses BeginDeferWindowPos, DeferWindowPos and EndDeferWindowPos.

Lastly, when I show/hide my window using the Visibility property instead of using Show() and Hide() the described behavior doesn't occur in some circumstances (more on that later) either. However, according to the documentation on msdn:

Calling Show achieves the same end result as setting Visibility property of the Window object to Visible. However, there is a difference between the two from a timing perspective. Calling Show is a synchronous operation that returns only after the Loaded event on the child window has been raised [...]

This seems very much related to operations being executed synchronously or asynchronously. In some scenarios I hide one particular window using user32's ShowWindow. If immediately after I show my window (using a shortcut key) the problem occurs again, regardless of whether I use Visibility or Show() to show the window. However, if I hide the window using ShowWindowAsync(), all is fine again.

Lastly ... (so many if's ... I know, sorry) when I click on any window (select it) prior to showing my window, the problem doesn't occur either. If I wouldn't be using a shortcut key to show the window I would have never found out about this.

What could be the root cause of this problem?

Steven Jeuris
  • 18,274
  • 9
  • 70
  • 161
  • You write: "*This one has me puzzled, and I am starting to believe it's a bug in either the core winapi, or possibly in WPF*" Comment without reading further: it's *exceedingly* unlikely that you discovered a genuine bug in the core WINAPI with a codepath as common as window visibility... and by *exceedingly* unlikely I mean basically impossible. – Nik Bougalis May 30 '13 at 23:51
  • @NikBougalis ... which is why I posted it here. ;p – Steven Jeuris May 31 '13 at 07:39

1 Answers1

0

I think I've identified the core issue which is causing this. When windows are hidden, another window is made active. However, it seems as if only windows present on the task bar are made active. When I hide all windows and afterwards call GetActiveWindow it indicates no window is active (return value null).

When subsequently a window is shown which shouldn't show up on the task bar (no matter whether Show() or Visibility is used) the hidden window is shown on the task bar.

A workaround which fixes this is checking after a deferred window positioning operation whether any window is active. If not, I now give focus to the task bar. Next time the non-taskbar window is shown, the bug doesn't occur!

succeeded = User32.EndDeferWindowPos( windowsPositionInfo );
if ( succeeded && User32.GetActiveWindow() == IntPtr.Zero )
{
    WindowInfo startBar = GetWindows()
        .Where( w => w.GetClassName() == "Shell_TrayWnd" ).FirstOrDefault();
    if ( startBar != null )
    {
        User32.SwitchToThisWindow( startBar.Handle, false );
    }
}
Steven Jeuris
  • 18,274
  • 9
  • 70
  • 161