Using binary data with process.standardInput/StandardOutput

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I am currently using the process class to successfully run .exe programs from
my VB.NET app redirecting stdin and out. This works fine when the input and
output streams are text.

I tried applying the same logic to files that are not ASCII text -- they are
PCL.

Below is the code I am using for text input. This does not work for PCL
files. I tried using the binary reader writer to no avail.

Any suggestions would be greatly appreciated!!

Thanks,
Hanika

Code:
Dim pInfo As New ProcessStartInfo
Dim timeOut As Integer = 5000
Dim filterLog As StreamWriter

With pInfo
.FileName = GetShortName(Me.mFilter)
.Arguments = Me.mFilterArgs
.WindowStyle = ProcessWindowStyle.Hidden
.CreateNoWindow = True
.UseShellExecute = False
.RedirectStandardError = True
.RedirectStandardOutput = True
.RedirectStandardInput = True
End With
Try
'Start the process.
Dim p As Process = Process.Start(pInfo)

'Write to standard Input
Dim fsr As StreamReader = New StreamReader(Me.mPath)
p.StandardInput.AutoFlush = True
p.StandardInput.Write(fsr.ReadToEnd)
fsr.Close()
p.StandardInput.Close()

'Log standard error
If p.StandardError.Peek <> -1 Then
filterLog = IO.File.CreateText(Me.mFilter & ".log")
filterLog.Write(p.StandardError.ReadToEnd)
filterLog.Close()
End If

'Write to stdOUt
Me.mFilteredData = Path.GetTempFileName
Dim fs As StreamWriter = IO.File.AppendText(Me.mFilteredData)
fs.Write(p.StandardOutput.ReadToEnd())
fs.Close()

p.WaitForExit(timeOut)
'HasExited is true if the application closed before the time-out.
If p.HasExited = False Then
'Process is still running.
'Test to see if process is hung up.
If p.Responding Then
'Process was responding; close the main window.
p.CloseMainWindow()
Else
'Process was not responding; force the process to close.
p.Kill()
End If
End If
 
This line is the problem
Dim fsr As StreamReader = New StreamReader(Me.mPath)

You are converting the input to text, UTF-7, which is probably not useful in
PCL.

You need to be reading with a binary reader (watch for wrap)
http://msdn.microsoft.com/library/d...cpconReadingWritingToNewlyCreatedDataFile.asp


--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
Thanks for your response.

I changed my code to use binary reader and access the basestream. I have
run into a new problem: The basestream write gets stuck when I try
propcessing files pver aprox 60 KB. It works fine for files under that size.
Here is my code:

Dim pInfo As New ProcessStartInfo
Dim timeOut As Integer = 5000
Dim Ascii As Encoding = Encoding.Default


Try
With pInfo
.FileName = FormFontRoot & "bin\findpage.exe"
.Arguments = PageNum.ToString & " " & PageNum.ToString
.WindowStyle = ProcessWindowStyle.Hidden
.CreateNoWindow = True
.UseShellExecute = False
.RedirectStandardError = True
.RedirectStandardOutput = True
.RedirectStandardInput = True
End With

'Start the process.
Dim p As Process = Process.Start(pInfo)

'Write to standard Input
Dim br As BinaryReader = New BinaryReader(File.Open(FileName,
FileMode.Open))
Dim Bytes(4096) As Byte
Dim BytesRead As Integer
Dim totalBytes As Integer = 0
While br.PeekChar <> -1
BytesRead = br.Read(Bytes, 0, Bytes.Length)
totalBytes = totalBytes + BytesRead

p.StandardInput.BaseStream.Write(Bytes, 0, BytesRead) '-->
stuck here

End While
br.Close()
p.StandardInput.Close()

''Write to stdOUt
Dim FileOut As String = FileName & ".p" & PageNum.ToString
If IO.File.Exists(FileOut) Then IO.File.Delete(FileOut)

Dim FileStrm As FileStream = New FileStream(FileOut, _
FileMode.CreateNew, FileAccess.Write, FileShare.Write)

Dim bw As BinaryWriter = New BinaryWriter(FileStrm)
BytesRead = p.StandardOutput.BaseStream.Read(Bytes, 0,
Bytes.Length)
While BytesRead <> 0
bw.Write(Bytes, 0, BytesRead)
BytesRead = p.StandardOutput.BaseStream.Read(Bytes, 0,
Bytes.Length)
End While
bw.Close()
p.StandardOutput.Close()

p.WaitForExit(timeOut)
 
Ah. I didn't think of that, but it makes perfect sense. I haven't solved
this problem before, but I've sure seen it.

History lesson: The notion of stdin and stdout comes from Unix. It was
adopted into DOS in its early days when C was becoming a popular way to
write programs for DOS. In Unix (of the time), stdin and stdout were simply
buffered pipes. In other words, you have a specific buffer size and, when
it is full, the process sending the data would be stopped until the process
receiving the data caught up and consumed it. DOS did its best to emulate
that. For the most part, they succeeded.

The problem is that this mechanism was designed for one app to pipe to
another, not for a controller app to pipe to a child. In other words, you
are supposed to give the command: "myapp | nextapp" at the command line, and
let DOS handle the controlling. In this context, 'myapp' is triggered and
runs until the buffer fills up. Then, 'nextapp' runs until the buffer is
largely consumed. Then 'myapp' continues until the buffer is full again...
and the dance goes on.

You haven't recreated this interaction in your app. Therefore, the buffer
fills and everything stops.

You could solve this by having a portion of your app run standalone, and use
the "pipe" notation above. Not elegant.

Alternative: write all of the data to a file and issue the command using the
"<" notation:

In other words, create a file that you intend to feed into input (I'll call
it "mytempfile.dat") and then issue the command:
"nextapp <mytempfile.dat"

Hope this helps

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
Hanika said:
Thanks for your response.

I changed my code to use binary reader and access the basestream. I have
run into a new problem: The basestream write gets stuck when I try
propcessing files pver aprox 60 KB. It works fine for files under that
size.
Here is my code:
<<code clipped>>
 
He could also write the commands to a batch file and then execute the batch
file....that allows the command processor to directly handle the piping
between the apps rather then redirecting standard input and output and
trying to achieve the same semantics as the command processor.
 
Back
Top