无法在 Process.Start 上最小化新进程 Window

Can't minimize the new Process Window on Process.Start

我需要从我的程序启动一个 java .jar 进程。
一旦开始,我就会得到输出并进行处理。

为此,我使用以下代码:

Dim p_Process As New Process()
Dim p_p As New ProcessStartInfo
p_p.FileName = "java.exe"
p_p.Arguments = "-jar myjar.jar"

p_p.WorkingDirectory = apppath & "\myFolder"

p_p.UseShellExecute = False
p_p.RedirectStandardOutput = True
p_p.WindowStyle = ProcessWindowStyle.Minimized
AddHandler p_Process.OutputDataReceived, AddressOf manageContent

p_Process.StartInfo = p_p
p_Process.Start()
p_Process.BeginOutputReadLine()

我需要以下几行才能获得供我使用的流程输出:

p_p.UseShellExecute = False
p_p.RedirectStandardOutput = True

一切正常,但 window 未最小化。
如何最小化window?

一种可能的方法是在 Java.exe 出现时使用 UI 自动化最小化 Window。
启动进程时,将执行 Jar 文件并创建一个新的 Window。此 Window 具有特定的 class 名称,SunAwtFrame:此值可用于识别 window,然后访问 UI Automation Element 的 WindowPattern and call its SetWindowVisualState() 方法来最小化 Window。

您也可以使用 Window 标题 属性,以防它是更好的选择。在这种情况下,PropertyCondition to identify the Window is the NameProperty instead of the ClassNameProperty

window = AutomationElement.RootElement.FindFirst(TreeScope.Children, New PropertyCondition(
    AutomationElement.NameProperty, "[The Window Title]"))

当然,Process 是完美的功能。

在这里,我使用异步变体实现它,重定向 StandardOutput 和 StandardError,还启用和订阅 Exited 事件,设置 [Process].EnableRaisingEvents = True.
Exited 事件通知进程何时关闭并处理进程 object。


此处的代码使用 StopWatch 等待进程的 Window 出现,因为 Process.WaitForInputIdle() 可能无法 正确处理 并完成太早了。
如果 3000 毫秒间隔太短或太长,请调整代码。
但是请注意,一旦 Window 出现,While 循环就会退出。

此代码需要引用 UIAutomationClientUIAutomationTypes 程序集。

Imports System.Windows.Automation

Dim proc As New Process()
Dim psInfo As New ProcessStartInfo() With {
    .FileName = "java.exe",
    .Arguments = "-jar YourJarFile.jar",
    .WorkingDirectory = "[Your Jar File Path]",
    .UseShellExecute = False,
    .RedirectStandardOutput = True,
    .RedirectStandardError = True
}

proc.EnableRaisingEvents = True
proc.StartInfo = psInfo

AddHandler proc.OutputDataReceived,
    Sub(o, ev)
        Console.WriteLine(ev.Data?.ToString())
    End Sub
AddHandler proc.ErrorDataReceived,
    Sub(o, ev)
        Console.WriteLine(ev.Data?.ToString())
    End Sub
AddHandler proc.Exited,
    Sub(o, ev)
        Console.WriteLine("Process Exited")
        proc?.Dispose()
    End Sub

proc.Start()
proc.BeginOutputReadLine()

Dim window As AutomationElement = Nothing
Dim sw1 As Stopwatch = New Stopwatch()
sw1.Start()
While True
    window = AutomationElement.RootElement.FindFirst(
        TreeScope.Children, New PropertyCondition(
        AutomationElement.ClassNameProperty, "SunAwtFrame"))
    If window IsNot Nothing OrElse sw1.ElapsedMilliseconds > 3000 Then Exit While
End While
sw1.Stop()

If window IsNot Nothing Then
    DirectCast(window.GetCurrentPattern(WindowPattern.Pattern), WindowPattern).
        SetWindowVisualState(WindowVisualState.Minimized)
End If