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!