最顶层 window 超过所有内容,子进程除外

Topmost window over everything, except child processes

我的程序是全屏和最顶层的,我希望 window 的所有子进程都在我程序的主进程 window 之上。这些过程是未知的,并且是外部的。

我可以使用 System.Diagnostics.Process.Start(exeName,procArgs).WaitForExit() 启动该进程,但从那里我卡住了。

基本上,您使用 SetParent() API 使外部应用程序成为您的子应用程序。在这里,我还使用 GetWindowRect() 和 SetWindowPos() APIs 将 window 在其父项更改后保持在相同的启动位置。最后,您需要跟踪进程并手动关闭它们,以便它们在关闭表单时不会成为孤立的:

Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions

Public Class Form1

    Private Const SWP_NOSIZE As Integer = &H0001

    <StructLayout(LayoutKind.Sequential)>
    Public Structure RECT
        Public Left As Integer, Top As Integer, Right As Integer, Bottom As Integer
    End Structure

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
    End Function

    <DllImport("user32.dll")>
    Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
    End Function

    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function SetWindowPos(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 Integer) As Boolean
    End Function

    Private Ps As New List(Of Process)

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim exeName As String = "Notepad"
        Dim procArgs As String = ""
        LaunchExe(exeName, procArgs)
    End Sub

    Private Sub LaunchExe(ByVal exeName As String, ByVal procArgs As String)
        Try
            Dim p As Process = System.Diagnostics.Process.Start(exeName, procArgs)
            If Not IsNothing(p) Then
                p.WaitForInputIdle()
                Dim rc As RECT
                GetWindowRect(p.MainWindowHandle, rc)
                Dim pt As New Point(rc.Left, rc.Top)
                pt = Me.PointToClient(pt)
                SetParent(p.MainWindowHandle, Me.Handle)
                SetWindowPos(p.MainWindowHandle, 0, pt.X, pt.Y, 0, 0, SWP_NOSIZE)
                Ps.Add(p)
            End If
        Catch ex As Exception
            MessageBox.Show(exeName & vbCrLf & procArgs, "Error Starting Application")
        End Try
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Me.Close()
    End Sub

    Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
        For Each P As Process In Ps
            If Not P.HasExited Then
                P.CloseMainWindow()
            End If
        Next
    End Sub

End Class