Display output of the CMD in real time inside TextBox

Ask questions about creating Graphical User Interfaces (GUI) in PowerShell and using WinForms controls.
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
User avatar
ALIENQuake
Posts: 30
Joined: Sun Mar 03, 2013 12:45 pm

Re: Display output of the CMD in real time inside TextBox

Post by ALIENQuake » Wed Sep 05, 2018 9:16 am

Well, here is another attempt:

- $count is an index of element from array of processes
- when the current process has exited i simply do: $script:count++
- SynchronizingObject has to be passed via parameter to the function
- it's possible to send input to the current app
- readinput process is readinput.exe from below code

It seems to behave exactly as I wanted. Let me integrate it and see final results. Amazing support by jvierra, thank you!

code for readinput.exe

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace readinput {
    class Program {
        static void Main( string[] args ) {
            Console.WriteLine("Read input");
            Console.WriteLine("");
            var s = Console.ReadLine();
            Console.WriteLine("Out from app:");
            Console.WriteLine(s);
            //Console.ReadKey();
        }
    }
}
Code for form:

Code: Select all

$code = @'
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
'@
Add-Type -MemberDefinition $code -Name Win32SetParent -Namespace Win32Functions

function Run-Process ($count, $sync) {
	
	$script:p = [System.Diagnostics.Process]::New() # has to be $script: because of buttonSendInput_Click > $p.StandardInput.WriteLin
	
	$p.add_Exited({
			#[System.Windows.Forms.MessageBox]::Show('Process Exited!')
			$script:count++
			if ($script:count -lt $dataP.count) {
				Run-Process -count $script:count -sync $form1
			}
		})
	
	$p.add_OutputDataReceived({
			$textbox2.Lines += $_.Data
			
			$textbox2.Select($textbox2.Text.Length, 0)
			$textbox2.ScrollToCaret()
		})
	
	$p.StartInfo.RedirectStandardOutput = $true
	$p.StartInfo.RedirectStandardError = $true
	$p.StartInfo.RedirectStandardInput = $true
	$p.StartInfo.UseShellExecute = $false
	#$p.StartInfo.CreateNoWindow = $true
	$p.StartInfo.FileName = $dataP[$count]
	$p.StartInfo.Arguments = '-n 3 google.com'
	$p.EnableRaisingEvents = $true
	$p.SynchronizingObject = $sync
	
	if ($script:count -lt $dataP.count) {
		$p.Start()
		do {
			Start-Sleep -Milliseconds 50
		} until ($p.MainWindowHandle)
		
		$p.BeginOutputReadLine()
		
		[Win32Functions.Win32SetParent]::SetParent($p.MainWindowHandle, $textbox1.Handle)
	}
}

$form1_Load = {
	#TODO: Initialize Form Controls here
	$global:dataP = 'ping', 'readinput', 'ping'
	$script:count = 0
}

$form1_FormClosing = [System.Windows.Forms.FormClosingEventHandler]{
	#Event Argument: $_ = [System.Windows.Forms.FormClosingEventArgs]
	Write-Host Form closing
}

$form1_FormClosed = [System.Windows.Forms.FormClosedEventHandler]{
	#Event Argument: $_ = [System.Windows.Forms.FormClosedEventArgs]
	Write-Host Form Closed
}

$form1_ParentChanged = {
	Write-Host Parent
}

$buttonRunProcess_Click = {
	#TODO: Place custom script here
	Run-Process -count $script:count -sync $form1
}


$buttonSendInput_Click = {
	#TODO: Place custom script here
	$p.StandardInput.WriteLine($textboxInput.Text)
	$p.StandardInput.WriteLine("`n") # simulate 'ENTER'
}

User avatar
jvierra
Posts: 13395
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Display output of the CMD in real time inside TextBox

Post by jvierra » Wed Sep 05, 2018 11:16 am

Synchronizing object must be the form:
$p.SynchronizingObject = $form1

"SetParent" is only used if you want to display the process window within a form object. If so then position and an location tracking (OnMove) must be implemented for this to display correctly.

User avatar
ALIENQuake
Posts: 30
Joined: Sun Mar 03, 2013 12:45 pm

Re: Display output of the CMD in real time inside TextBox

Post by ALIENQuake » Wed Sep 05, 2018 12:55 pm

jvierra wrote:
Wed Sep 05, 2018 11:16 am
Synchronizing object must be the form:
$p.SynchronizingObject = $form1
It is: it's passed via -sync $form1 parameter
jvierra wrote:
Wed Sep 05, 2018 11:16 am
"SetParent" is only used if you want to display the process window within a form object. If so then position and an location tracking (OnMove) must be implemented for this to display correctly.
Yep, it's nice to see process windows inside application window, not flying around whole desktop

User avatar
jvierra
Posts: 13395
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Display output of the CMD in real time inside TextBox

Post by jvierra » Wed Sep 05, 2018 1:18 pm

You redirected errors but did not provide:

$p.add_ErrorDataReceived({ .. })
$p.BeginErrorReadLine()


If you are redirecting all output then the process Window is unnecessary. Just set "CreateNoWindow" and it will not be visible.

Locked