1

I need to start a java .jar process from my program.
Once started, I get the output and I process it.

For this, I use the following code:

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()

I need the following lines in order to get the output of the Process for my use:

p_p.UseShellExecute = False
p_p.RedirectStandardOutput = True

All is working, but the window is not minimized.
How to minimize the window?

Jimi
  • 29,621
  • 8
  • 43
  • 61
ManRas
  • 57
  • 7
  • `WindowState.Minimized`, are you sure? Do you have `Option Strict On`? Have you tried `ProcessWindowStyle.Minimized` instead? And `p_p.UseShellExecute = True`? Or maybe you want to hide the Window instead? – Jimi Apr 16 '20 at 07:00
  • The documentation for the `WindowsStyle` property contains a code example that shows it being set to `ProcessWindowStyle.Minimized`, not `WindowState.Minimized`. ALWAYS read the documentation. – jmcilhinney Apr 16 '20 at 07:19
  • @Jimi, the documentation for `UseShellExecute` says *"If you set the `WindowStyle` to `ProcessWindowStyle.Hidden`, `UseShellExecute` must be set to `true`"*, so no issue in this case. – jmcilhinney Apr 16 '20 at 07:21
  • @jmcilhinney The question has been edited since when I posted that comment. The OP, initially, forgot to mention that they needed to use `RedirectStandardOutput = True`. So I hinted that, maybe, they could use `ShellExecute = True` to get the minimized (or hidden) effect. Now it doesn't apply anymore. But you can minimized it anyway. PInvoking, with UI Automation etc. – Jimi Apr 16 '20 at 07:29
  • @Jimi: sorry, was a mistake in passing the code here. I use ProcessWindowStyle.Minimized. Regarding p_p.UseShellExecute, it must be false in order to redirect the output. if set to true, can't redirect. – ManRas Apr 16 '20 at 12:20

1 Answers1

1

A possible approach is to minimize the Window generated by Java.exe, when it shows up, using UI Automation.
When the Process is started, the Jar file is executed and a new Window is created. This Window has a specific class name, SunAwtFrame: this value can be used to identify the window, then access the UI Automation Element's WindowPattern and call its SetWindowVisualState() method to minimize the Window.

You can also use the Window Title property, in case its a better choice here. In this case, the 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]"))

Of course, the Process is perfectly functional.

Here, I've implemented it using the asynchronous variant, redirecting StandardOutput and StandardError, also enabling and subscribing to the Exited event, setting [Process].EnableRaisingEvents = True.
The Exited events notifies when the Process is closed and also disposes of the Process object.


The code here uses a StopWatch to wait for the Process' Window to show up, since Process.WaitForInputIdle() may not be get it right and complete too soon.
Adjust the code if 3000 milliseconds is a too short or too long interval.
Note, however, that as soon as the Window shows up, the While loop is exited.

This code requires a reference to the UIAutomationClient and UIAutomationTypes assemblies.

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
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • then, if i understand correctly the above code is for call the setWindowVisualState function. Is right? If yes, there is the same than using ShowWindow funcion or not? – ManRas Apr 16 '20 at 13:08
  • This code is meant to handle the Process StandardOutput and StandardError and the Process termination asynchronously (event-based). Then, to minimize the new Process Window without PInvoking. You could also use a Win32 function to accomplish this last task, that's for sure. But you have to know when to call it. The code here does everything without specific requirements. It could also be modified to auto-detect the opening of the Window, no matter how many identical Windows are opened at a point in time. – Jimi Apr 16 '20 at 13:11
  • i have just tested your code but nothing happens. Black window continues in normal state :-( – ManRas Apr 16 '20 at 13:23
  • If you have used this code correctly and it doesn't detect the new Window, there's a chance that the Window class name is not `SunAwtFrame`. You can use Spy++ or `Inspect` to determine the Window class name. Or use the Window Title, as described in the notes. `Inspect` can be found in `C:\Program Files (x86)\Windows Kits\10\bin\x64\inspect.exe` (or whatever other disc your System is installed in). – Jimi Apr 16 '20 at 13:25
  • `ConsoleWindowClass`? That's weird (well, at least it's not what I thought). So, it's not a standard Win32 Window, it's a Console. Anyway, in case you're interested, this code also works with standard Windows. Meaning, you can get the `StandardOutput` also from a standard Win32 Window created by `java.exe` through a `.jar` file. – Jimi Apr 16 '20 at 13:50
  • all is working. the solution is ok for me. :-) i have arrived to similar point changing the window position taking handle from p_Process: MoveWindow(p_Process.MainWindowHandle, 60, 60, 60, 60, True) – ManRas Apr 16 '20 at 13:54
  • the problem is the window appears before disappear... i will need something to avoid the window to be visible (that what im looking for with the minimize solution) to users on start... – ManRas Apr 16 '20 at 14:07
  • Have you tried adding `.CreateNoWindow = True` to ProcessStartInfo, to see what happens: since it's just a Console Window, it may also not appear at all. – Jimi Apr 16 '20 at 14:11
  • i really dont understand... i was testing this during the long hours spent with this and now i look that works perfectly with createNoWindow... im lost. thanks in any way for all. – ManRas Apr 16 '20 at 14:19
  • I would have suggested that right away but for some reason I got stuck thinking this was a standard Win32 (graphic) Window. Who knows why. Since it's a Console Window, don't remove `RedirectStandardError`, you'll need it. [This other code](https://stackoverflow.com/a/51682585/7444103) may come in handy, too. – Jimi Apr 16 '20 at 14:35
  • Set `proc.SynchronizingObject = Me` (or the instance of the Form parent of the TextBox). Then simply `TextBox1.AppendText(ev.Data?.ToString() & vbNewLine)`. Setting the SynchronizingObject causes the event to raise in the UI Thread instead of a ThreadPool Thread. Otherwise you can `BeginInvoke()` a Control (it's shown in the code I linked in a previous comment). – Jimi Apr 16 '20 at 15:56
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/211827/discussion-between-manras-and-jimi). – ManRas Apr 16 '20 at 18:56