I'm writing a little utility to allow me to multiplex input to multiple terminal windows;
Any input received by the form (in the centre) is relayed to all terminal windows it manages.
This works well but a problem occurs if I another window moves in front of the terminals. The input form is Topmost
so is always visible, but the terminal sessions are hidden.
To work around this, double-clicking on the Input window iterates through all the terminals and calls SetForegroundWindow
(from user32.dll
) on each in turn.
For Each Manager In Managers
SetForegroundWindow(ProcessInfo.MainWindowHandle)
'Threading.Thread.Sleep(15)
Next
If I make this call without the Thread.Sleep(15)
, only the first and last window in the list are brought to the foreground. The Sleep
works around the problem but is a bit of a hack (and is a little ugly when there are a lot of terminals open).
I assume I'm hitting some internal windows tick frequency where at most one window can be brought to the front per tick.
Am I correct in my assumption? And is there a way around this limitation? Something like a MoveAllToForeground()
or a way of queueing the messages?
Edit:
To clarify: The terminal process I'm automating is not part of my application, it's PuTTY
If I swap out the call to SetForegroundWindow
for BringWindowToTop
, I get a similar issue - although in this case, only the first of the terminals is brought to the front, the rest stay behind any other windows.
Edit 2:
Following on from David's suggestion below. The declarations:
Private Declare Auto Function SetWindowPos Lib "user32.dll" (
ByVal hWnd As IntPtr,
ByVal hWndInsertAfter As IntPtr,
ByVal X As Integer,
ByVal Y As Integer,
ByVal cx As Integer,
ByVal cy As Integer,
ByVal uFlags As SetWindowPosFlags
) As Boolean
Private Shared ReadOnly HWND_TOPMOST As New IntPtr(-1)
Private Shared ReadOnly HWND_NOTOPMOST As New IntPtr(-2)
Private Shared ReadOnly HWND_TOP As New IntPtr(0)
Private Shared ReadOnly HWND_BOTTOM As New IntPtr(1)
Private Enum SetWindowPosFlags
NOSIZE = &H1
NOMOVE = &H2
NOZORDER = &H4
NOREDRAW = &H8
NOACTIVATE = &H10
DRAWFRAME = &H20
FRAMECHANGED = &H20
SHOWWINDOW = &H40
HIDEWINDOW = &H80
NOCOPYBITS = &H100
NOOWNERZORDER = &H200
NOREPOSITION = &H200
NOSENDCHANGING = &H400
DEFERERASE = &H2000
ASYNCWINDOWPOS = &H4000
End Enum
And the call...
SetWindowPos(ProcessInfo.MainWindowHandle,
HWND_TOP,
0, 0, 0, 0,
SetWindowPosFlags.NOMOVE Or
SetWindowPosFlags.NOSIZE Or
SetWindowPosFlags.NOACTIVATE)