1

I have a bunch of forms, some created from the main thread and some from other threads.

Suppose I open all these forms on the screen. If I open another window on top of them (eg. Google Chrome) and then click on my application in the windows bar, only the forms created from my main thread are brought to front. I need to have all of them in front, but without giving them focus.

This appears to be a Windows bug from what I found out.

The following work-around works for bringing the windows to front:

private const int WM_WINDOWPOSCHANGING = 0x0046;

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
         case WM_WINDOWPOSCHANGING:
              if (Control.FromHandle(m.LParam) == null)
              {
                  var openForms = this.GetOpenForms();
                  foreach (var openForm in openForms)
                  {
                      ShowInactive(openForm, true);
                  }
              }
              break;
      }

      base.WndProc(ref m);
}

Where GetOpenForms() returns the list of forms opened by the application. The ShowInactive(...) function is defined below:

private static void ShowInactive(Form frm, bool topMost)
{
     if (frm.InvokeRequired)
     {
         frm.Invoke(new MethodInvoker(() => ShowInactive(frm, topMost)));
         return;
     }

     const int SWP_SHOWWINDOW = 0x0040;
     const int SWP_NOSIZE = 0x0001;
     const int SWP_NOMOVE = 0x0002;

     User32.SetWindowPos(
         frm.Handle.ToInt32(),
         topMost ? User32.HWND_TOPMOST : User32.HWND_NOTOPMOST,
         0,
         0,
         0,
         0,
         User32.SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
    }

I already tested this approach and seems to be working fine if other windows are on top of my mine. However, after having positioned the windows on top, I should override their TopMost property to false so that they will not remain like this forever.

Basically, I need to call ShowInactive(frm, false) for each form in my list. The question is where and when (could not find any event telling me that all the forms have had their z-order changed or one that could guarantee me that).

I appreciate any help! Thanks!

Mirel Vlad
  • 2,032
  • 3
  • 27
  • 35
  • This is by design, the owner of a collection of windows is a thread, not a process. There are many nasty traps in creating a window on another thread, this is just the mild version. The SystemEvents class falls in the Really Nasty category, it will raise its events on the wrong thread and deadlock your program. Many controls subscribe its UserPreferenceChanged event to repaint themselves. Don't do it. – Hans Passant Mar 24 '14 at 11:23
  • Is there another work-around? – Mirel Vlad Mar 24 '14 at 11:29
  • Marshal all UI related calls (including creation of the "other" windows) to the UI thread using .BeginInvoke on the main form (which should be running on the UI thread). – Bradley Uffner Mar 24 '14 at 12:59

0 Answers0