Need to create a wrapper to execute a program

T

Tony Freixas

Hello,

I'm trying to create a wrapper for a program. I want to execute
program 'X' by running program 'Y', such that 'Y' appears to function
pretty much like 'X' both in the way command line options are handled
and the way input, output and error messages are reported. Program 'X'
is a console application.

I had it pretty well figured out, I thought, until I ran into a case
where program X spit out ZIP code. In other words, I was reading
Process.StandardOutput.ReadLine() and writing to Console.WriteLine().
These don't handle binary output very well.

So I can read X's output using
Process.StandardOutput.BaseStream.ReadByte() but I can't find the
right method to write binary to Y's standard output. How do I convert
Console.Out to a StreamWriter? I want this to work efficiently, too.

Here's the program so far. Thanks for any suggestions.

using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;

namespace TigerHeron.CoreLib
{
public class ProgramExecute
{
public const int NONE = 0;
public const int REDIRECT_IO = 1;
private Process process;

public ProgramExecute(string[] args) : this(args, NONE)
{
}

public ProgramExecute(string[] args, int flags)
{
if (args.Length < 1) {
throw new ArgumentException("The array must have at least one
argument", "args");
}

process = new Process();
String program = args[0];

string newArgs = "";
for (int i = 1; i < args.Length; i++) {
newArgs += "\"" + args + "\" ";
}
process.StartInfo.FileName = program;
process.StartInfo.Arguments = newArgs;

if ((flags & REDIRECT_IO) != 0) {
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
}

process.StartInfo.Verb = "Open";
process.StartInfo.UseShellExecute = (flags & REDIRECT_IO) == 0;
process.StartInfo.ErrorDialog = (flags & REDIRECT_IO) == 0;
process.StartInfo.CreateNoWindow = true;
process.Start();

if ((flags & REDIRECT_IO) != 0) {
new Thread(new ThreadStart(this.readStdin)).Start();
new Thread(new ThreadStart(this.readStdout)).Start();
new Thread(new ThreadStart(this.readStderr)).Start();
process.WaitForExit();
Environment.Exit(process.ExitCode);
}
}

private void readStdin()
{
try {
string line;
while ((line = Console.In.ReadLine()) != null) {
process.StandardInput.WriteLine(line);
}
}
catch (Exception e) {
Console.Error.WriteLine(e.Message);
}
}

private void readStdout()
{
try {
int b;
while ((b = process.StandardOutput.BaseStream.ReadByte()) != -1) {
Console.Write((char)b); // This doesn't work
}
}
catch (Exception e) {
Console.Error.WriteLine(e.Message);
}
}

private void readStderr()
{
try {
string line;
while ((line = process.StandardError.ReadLine()) != null) {
Console.Error.WriteLine(line);
}
}
catch (Exception e) {
Console.Error.WriteLine(e.Message);
}
}
}
}
 
M

Moty Michaely

Hello,

I'm trying to create a wrapper for a program. I want to execute
program 'X' by running program 'Y', such that 'Y' appears to function
pretty much like 'X' both in the way command line options are handled
and the way input, output and error messages are reported. Program 'X'
is a console application.

I had it pretty well figured out, I thought, until I ran into a case
where program X spit out ZIP code. In other words, I was reading
Process.StandardOutput.ReadLine() and writing to Console.WriteLine().
These don't handle binary output very well.

So I can read X's output using
Process.StandardOutput.BaseStream.ReadByte() but I can't find the
right method to write binary to Y's standard output. How do I convert
Console.Out to a StreamWriter? I want this to work efficiently, too.

Here's the program so far. Thanks for any suggestions.

using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;

namespace TigerHeron.CoreLib
{
public class ProgramExecute
{
public const int NONE = 0;
public const int REDIRECT_IO = 1;
private Process process;

public ProgramExecute(string[] args) : this(args, NONE)
{
}

public ProgramExecute(string[] args, int flags)
{
if (args.Length < 1) {
throw new ArgumentException("The array must have at least one
argument", "args");
}

process = new Process();
String program = args[0];

string newArgs = "";
for (int i = 1; i < args.Length; i++) {
newArgs += "\"" + args + "\" ";
}
process.StartInfo.FileName = program;
process.StartInfo.Arguments = newArgs;

if ((flags & REDIRECT_IO) != 0) {
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
}

process.StartInfo.Verb = "Open";
process.StartInfo.UseShellExecute = (flags & REDIRECT_IO) == 0;
process.StartInfo.ErrorDialog = (flags & REDIRECT_IO) == 0;
process.StartInfo.CreateNoWindow = true;
process.Start();

if ((flags & REDIRECT_IO) != 0) {
new Thread(new ThreadStart(this.readStdin)).Start();
new Thread(new ThreadStart(this.readStdout)).Start();
new Thread(new ThreadStart(this.readStderr)).Start();
process.WaitForExit();
Environment.Exit(process.ExitCode);
}
}

private void readStdin()
{
try {
string line;
while ((line = Console.In.ReadLine()) != null) {
process.StandardInput.WriteLine(line);
}
}
catch (Exception e) {
Console.Error.WriteLine(e.Message);
}
}

private void readStdout()
{
try {
int b;
while ((b = process.StandardOutput.BaseStream.ReadByte()) != -1) {
Console.Write((char)b); // This doesn't work
}
}
catch (Exception e) {
Console.Error.WriteLine(e.Message);
}
}

private void readStderr()
{
try {
string line;
while ((line = process.StandardError.ReadLine()) != null) {
Console.Error.WriteLine(line);
}
}
catch (Exception e) {
Console.Error.WriteLine(e.Message);
}
}
}

}


Dear Tony,

stdout/stdin can't output or input binary data. It's purpose is to
output/input charecters, depending on encoding settings.

Using BaseStream is not a good way since the StandardOutput is a
wrapper to the base stream. You can't be sure the wrapper doe's
exactly what the base stream does.


If you need to redirect binary data, you should use other methods to
achieve this purpose.
 

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