Question

I'm writing a little utility to allow me to multiplex input to multiple terminal windows;

enter image description here

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)
Était-ce utile?

La solution

Apparently you want to bring these windows to the front rather than make them be the foreground window. The way to do that is to call SetWindowPos passing HWND_TOP. You'll need to pass SWP_NOMOVE | SWP_NOSIZE as the uFlags parameter since you only want to change the z-order, and not the position and size.

After each call to SetWindowPos, call SetForegroundWindow passing your application's main window handle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top