system.Diagnostics.Process Problem

G

Guest

Hello,

I am attempting to start a cmd.exe process and pass several .vbs scripts
(with additional parameters) and then read the output from the scripts and
make "notes" in a DataTable (the "notes" not being the issue).

Beginning with...

Dim objProcess As Process
Dim objProcessStartInfo As New ProcessStartInfo

objProcessStartInfo.FileName =
System.Environment.GetEnvironmentVariable("ComSpec")
objProcessStartInfo.WorkingDirectory =
System.Environment.GetEnvironmentVariable("SystemRoot")
objProcessStartInfo.RedirectStandardOutput = True
objProcessStartInfo.RedirectStandardInput = True
objProcessStartInfo.RedirectStandardError = True
objProcessStartInfo.UseShellExecute = False
objProcessStartInfo.WindowStyle = ProcessWindowStyle.Normal
objProcess = Process.Start(objProcessStartInfo)

I then loop through a DataTable, attempting to fire off VBScripts (or
Batch/EXE)(a.k.a. strApplicationAction) using:
objProcess.StandardInput.WriteLine(strApplicationAction)
Ex. strApplicationAction = "C:\Scratch\CopyFile.vbs MyComputer"

then attempt to read the output from the VBScript using
objProcess.StandardOutput. I have tried all of the following:

' Problem: EndOfStream is not reached when VBScript ends only when cmd.exe
closes.
Do While (objProcess.StandardOutput.EndOfStream = False)
strOutput &= objProcess.StandardOutput.ReadLine & vbCrLf
Loop

' Problem: Hangs because it is looking for the exit of the cmd.exe
strOutput = objProcess.StandardOutput.ReadToEnd

' If condition not reached until cmd.exe is closed
Do While (objProcess.StandardOutput.EndOfStream = False)
strTemp &= objProcess.StandardOutput.ReadLine
if (strTemp = System.Environment.GetEnvironmentVariable("SystemRoot") &
">") then exit do
Loop

Note: I can collect the StandardOutput. I am just getting tripped up on
knowing when the cmd.exe is idle. What I am looking for is the ability to
determine if the cmd.exe is finished processing the first VBScript/Batch/EXE
and then fire another one using
objProcess.StandardInput.WriteLine(strApplicationAction) without having to
launch a new cmd.exe for each ApplicationAction (I already have that working
~ 100 scripts = 100 cmd.exe (or cscript.exe)). Is it even possible to read
the status of cmd.exe? Do I need to use StandardError somehow? I have
already tried WaitForInputIdle (GUI only).

Thanks in advance.
 
M

Michael M.

I have noticed that when applications such as cscript % are executing the
title of CMD changes to somthing like

"C:\windows\system32\cmd.exe - Cscript AD_addNew.vbs"

then... once finished it changes back to

"C:\windows\system32\cmd.exe"

If you use sendmessage(hwnd, WM_GETTEXT, param, param)

You could read the CMD's caption.

infact I seem to remember the Process class has a method that reads the
caption of the main window of an application.

Mike.
 
G

Guest

Hello Mike,

Thanks for you response. Yes, I've seen that as well (happens with any
command sent to the cmd.exe) but I am not clear on your response. Why do I
need to read the CMD's caption? I looked up sendmessage and was unable to
determine the route that you are suggesting. I have an open connection the
process, I just need to be able to identify when the cmd.exe has finished
processing the previous command that was sent so that I may send another one.

Thank you
 
M

Michael M.

Dim consoleApp As New Process

With consoleApp

..StartInfo.UseShellExecute = False

..StartInfo.RedirectStandardOutput = True

..StartInfo.FileName = "cmd"

..StartInfo.RedirectStandardInput = True

..Start()

..WaitForExit(1)

End With

'Wait for the command window to load

Threading.Thread.Sleep(500)

Do

Me.Text = (consoleApp.MainWindowTitle.ToString)

Application.DoEvents()

Loop Until consoleApp.MainWindowTitle.ToString.Length <> 0

Application.DoEvents()

consoleApp.StandardInput.WriteLine("echo off")

Application.DoEvents()

consoleApp.StandardInput.WriteLine("cls")

Application.DoEvents()

consoleApp.StandardInput.WriteLine("ipconfig /DisplayDns")



Do

Application.DoEvents()

Me.Text = ("waiting for ipcfg to complete")

Loop Until consoleApp.MainWindowTitle.ToString.EndsWith("cmd.exe")

Me.Text = "ip cfg completed"
 
G

Guest

Hello Mike,

That's just plain slick. As an FYI, I also needed to capture the output and
parse it and threw in a time out in case it hangs. So I thought I would post
back what I did.

Select Case True
<Several cases to set things up>
Case else
objDateTime = DateTime.Now
objProcess.StandardInput.WriteLine(strApplicationAction)
Do
System.Windows.Forms.Application.DoEvents()
If (DateDiff(DateInterval.Minute, objDateTime, DateTime.Now) > 10) Then
Exit Select
Loop Until (objProcess.MainWindowTitle.ToString.EndsWith("cmd.exe") = True)
objProcess.StandardInput.WriteLine("Done!")
objDateTime = DateTime.Now
Do
strOutput &= objProcess.StandardOutput.ReadLine & vbCrLf
If (DateDiff(DateInterval.Second, objDateTime, DateTime.Now) > 5) Then
Exit Select
Loop Until (InStr(strOutput, "Done!") > 0)

Thanks again!
Gregory
 
M

Michael M.

No problem.

Mike.
gmyers said:
Hello Mike,

That's just plain slick. As an FYI, I also needed to capture the output
and
parse it and threw in a time out in case it hangs. So I thought I would
post
back what I did.

Select Case True
<Several cases to set things up>
Case else
objDateTime = DateTime.Now
objProcess.StandardInput.WriteLine(strApplicationAction)
Do
System.Windows.Forms.Application.DoEvents()
If (DateDiff(DateInterval.Minute, objDateTime, DateTime.Now) > 10) Then
Exit Select
Loop Until (objProcess.MainWindowTitle.ToString.EndsWith("cmd.exe") =
True)
objProcess.StandardInput.WriteLine("Done!")
objDateTime = DateTime.Now
Do
strOutput &= objProcess.StandardOutput.ReadLine & vbCrLf
If (DateDiff(DateInterval.Second, objDateTime, DateTime.Now) > 5) Then
Exit Select
Loop Until (InStr(strOutput, "Done!") > 0)

Thanks again!
Gregory
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top