• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1267
  • Last Modified:

interacting with a process

Hello, I am attempting to interact with a process that I launch. I need to monitor its output and enter key strokes in response to the output from the process. I cannot wait for the process to exit before seeing and responding to its output. Here is a simple example of what I am talking about as what you would see if using a cmd window:

C:\STMFlashLoader.exe -c --pn 17 --br 115200
Opening Port              [OK]
 Press any key to continue...

I have code working that allows me to monitor the output, but am unable to "send keys" with stream or sendkeys. I would like a structure such that I can monitor the output and when I see certain strings, respond by sending an appropriate string back to the process, and continue to monitor and again, send an appropriate string until the process exits or I terminate the process.

Here is the code I have working at this point


Dim start_info As New ProcessStartInfo("C:\Program Files\STMicroelectronics\Software\Flash Loader Demonstrator\STMFlashLoader.exe")
start_info.Arguments = "-c --pn 17 --br 115200"
start_info.UseShellExecute = False
start_info.CreateNoWindow = True
start_info.RedirectStandardOutput = True
start_info.RedirectStandardError = True

 ' Make the process and set its start information.
  Dim proc As New Process()
  proc.StartInfo = start_info

    ' Start the process.
     proc.Start()


  ' Attach to stdout and stderr.
  Dim std_out As StreamReader = proc.StandardOutput()
   Dim std_err As StreamReader = proc.StandardError()

       
        ' Display the results.
  txtStdout.Text = std_out.ReadToEnd()
   txtStderr.Text = std_err.ReadToEnd()

    ' Clean up.
  std_out.Close()
  std_err.Close()
   proc.Close()

Much thanks,
bartj












0
bartdsp
Asked:
bartdsp
  • 6
  • 4
  • 3
  • +2
2 Solutions
 
Mohamed AbowardaSoftware EngineerCommented:
To get the keystrokes, get the window handle and whenever the window is active use GetAsyncKeyState API:

http://msdn.microsoft.com/en-us/library/ms646293(v=VS.85).aspx
0
 
InteqamCommented:
i think this depends on the application, what if the process is windowless?!
0
 
bartdspAuthor Commented:
Inteqam,

Note sure I understand your question. The exe(STMFlashLoader.exe) that I "call", does have a window(DOS) when called from the command line, but if you are asking  if it needs to be visible, the answer is no. Let me know if that answers your question.

Thanks,
Bart




0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
InteqamCommented:
yes,
so, how are you to record actions on it if it is not visible?
0
 
bartdspAuthor Commented:
As you can see from my code example I I can monitor the output via re-directed stdout. In this case I have it sent to a text box. This could just as easily be directed to string (buffer) where I could monitor the output instead of a textbox.

Make sense?
0
 
mastooCommented:
I think we're saying it is a console application so windows messaging doesn't help.  Interprocess Communication can range from writing to a file (and the other app polls the file), to sockets or named pipes, or you could make a remoting server component.  I'd be inclined to just poll a file unless you need a better response, then named pipes are old fasioned but easy to do.  You can easily use a named mutex with a file to avoid the two programs running into each other on file access.
0
 
bartdspAuthor Commented:
Besides needing to grab the data (file, pipes, sockets, etc) there is the need to send  characters to the console application.
0
 
mastooCommented:
Can't say I'm an expert in this area but I think the only way to do that is your app needs to redirect stdin also.  Your app can then feed characters to stdin of the console app.  So now the question becomes, how does your app know what to feed it?  It either gets this from elsewhere (a file, pipes, sockets, etc.) or it could easily be a gui that is displaying stdout results and accepting or deciding on things to send to stdin.
0
 
bartdspAuthor Commented:
I was attempting to re-direct stdin but was having problems with implementation. I would imagine the code would spin in a loop while the app is still responding, looking for (for example): "press any key to continue" If that string is found, the app would send a space key, then continue to look for similar messages.

The 2 basic criteria: Receive data while the console app is running(not after it has terminated) and be able to send characters to the console app.

0
 
mastooCommented:
You'll need asynchronous redirection.  If you look at your VS help, Process.BeginOutputReadLine has an example.  It is complicated, but I think it is the only way to do what you describe.  I'm assuming here that you don't have the option of modifying the console app that you are invoking.
0
 
InteqamCommented:
I apologise, my comment was for Medo3337.

0
 
matrixnzCommented:
Here is how I'd do it in AutoIT which is based on the same principal, basically capture the output in a loop and as you suggested send keys then wipe the output so that it doesn't continue to hit the send key.

For more instructions just use elseif StringInStr($CHK_FLASHLOADER, .... etc.. and add other send keys.

Hope that made sense.

Cheers
#NoTrayIcon
#include <Constants.au3>

$RUN_FLASHLOADER = Run('"' & @ProgramFilesDir & '\STMicroelectronics\Software\Flash Loader Demonstrator\STMFlashLoader.exe" -c --pn 17 --br 115200', '', @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
$CHK_FLASHLOADER = ''
$ERR_FLASHLOADER = ''

	While 1
		$CHK_FLASHLOADER &= StdoutRead($RUN_FLASHLOADER)
		If @error Then ExitLoop
		If StringInStr($CHK_FLASHLOADER, 'Press any key to continue...') Then
			Send('{Space}')
			$CHK_FLASHLOADER = ''
		EndIf
	WEnd

	While 1
		$ERR_FLASHLOADER &= StderrRead($RUN_FLASHLOADER)
		If @error Then ExitLoop
	WEnd

Open in new window

0
 
bartdspAuthor Commented:
All,

I tried the following and am still unable to monitor the process until after the exe that I am calling has exited. Note that I have a timer firing every 200 ms in an attempt to gather the data and display. I am not yet attempting to send keys. If I send the exe name and parameters in a dos window I get streaming data in a dos window for 20 seconds telling me about the process. If sending via my code I get the data only after 20 seconds has elapsed.

Comments?....

Sub ProcessTest()


        Try
            ' Initialize the process and its StartInfo properties.
            Dim myProcess As New Process()
            Dim numInputLines As Integer = 0

            Bigmessage = ""


            myProcess.StartInfo.FileName = "C:\Program Files\STMicroelectronics\Software\Flash Loader Demonstrator\STMFlashLoader.exe"
            myProcess.StartInfo.Arguments = "-c --pn 17 --br 115200 -i STM32_Med-density_128K -u --fn c:\qaz.hex"

            ' Set UseShellExecute to false for redirection.
            myProcess.StartInfo.UseShellExecute = False

            ' Redirect the standard output of the sort command.  
            ' Read the stream asynchronously using an event handler.
            myProcess.StartInfo.RedirectStandardOutput = True
            sortOutput = New StringBuilder()

            ' Set our event handler to asynchronously read the sort output.
            AddHandler myProcess.OutputDataReceived, AddressOf MyOutputHandler

            ' Redirect standard input as well.  This stream is used synchronously.
            myProcess.StartInfo.RedirectStandardInput = True

            ' Start the process.
            myProcess.Start()

            ' Use a stream writer to synchronously write .
            Dim myStreamWriter As StreamWriter = myProcess.StandardInput

            ' Start the asynchronous read of the sort output stream.
            myProcess.BeginOutputReadLine()

            ' End the input stream to the sort command.
            myStreamWriter.Close()

            ' Wait
            myProcess.WaitForExit()


            myProcess.Close()


        Catch

            MsgBox("Process test: " & Err.Description)
        End Try

    End Sub

    Sub MyOutputHandler(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)


        Try
            Dim msg As String

            Application.DoEvents()

            If outLine.Data.ToString = Nothing Then Exit Sub
           
            msg = outLine.Data.ToString

            If Not msg = "" Then

                Bigmessage = Bigmessage & msg
                numOutputLines = numOutputLines + 1

            End If

        Catch

            MsgBox("Handler: " & Err.Description)

        End Try

    End Sub
0
 
mastooCommented:
This runs from a gui with a timer that is checking Bigmessage?

Two things I note: I assume MyOutputHandler gets its callback from a background thread, so DoEvents and MsgBox shouldn't be used there.  And is the other app looking for input on stdin?  I'm not sure how it will react but you close the redirected input stream immediately.  This is why I said it would be complicated.  I'm thinking you need to keep the input stream open while watching the output from stdout, and respond on stdin based on what stdout does.
0
 
bartdspAuthor Commented:
All, I ended up getting my hands on the source for the console app and modified so that I did not need to send it any key info. Then I used a process and a handler:

            ' define a process
            Dim p As New Process

            p.StartInfo.FileName = filename
            p.StartInfo.Arguments = parametrers

            ' setup
            p.StartInfo.UseShellExecute = False
            p.StartInfo.RedirectStandardOutput = True
            p.StartInfo.CreateNoWindow = True

            ' add a handler so we can easily display the data
            AddHandler p.OutputDataReceived, AddressOf Showme
           
            p.Start()
            p.BeginOutputReadLine()

            Application.DoEvents()

            ' spin here till done or cancel
            Do While (p.HasExited = False) And (CANCEL = False)
                ' monitor progress
                Application.DoEvents()
            Loop

            If CANCEL = True Then
                p.Kill()
                p.Dispose()
                Return False
            End If

            p.Dispose()
            Return true

   
    End Function
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 6
  • 4
  • 3
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now