strange behaviour on another process via Process.Start(startInfo) - c#

Our C# (V3.5) application needs to call another C++ executable which is from another company. we need to pass a raw data file name to it, it will process that raw data (about 7MB) file and generate 16 result files (about 124K for each).
The code to call that executable is this:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = exePath;
startInfo.Arguments = rawDataFileName;
try
{
Process correctionProcess = Process.Start(startInfo);
correctionProcess.WaitForExit();
}
catch(nvalidOperationException ex)
{
....
}
catch(...)
...
It works fine. Now we have new raw data. After replace the old raw data with the new raw data file. That executable process never return to us. It will hang forever. If we kill our C# application, those result files will be generated in the target directoy. It looks like the executable does create those result files but has issue to write to the disk and return to us until the process is terminated.
It is NOT like this with the old raw data file.
When we run the executable with the new raw data directly (no from our C# app call), it works fine. This means this executable has no problem with the new raw data.
My question 1: what's the possible causes for this behaviour?
Now I change our code with startInfo.UseShellExecute = true; and add startInfo.WorkingDirectory= ..., and disabled
//startInfo.RedirectStandardError = true;
//startInfo.RedirectStandardOutput = true;
Then it works.
My question 2: why use Windows Shell solve this issue?
My question 3: why it works before without using Shell?
My question 4: when we should use Shell and When shouldn't?
thanks,

Several possibilities:
You are redirecting output and error but not reading it. The process will stall when its stdout or stderr buffer fills up to capacity.
The program might be displaying an error message and waiting for a keypress. You are not redirecting input nor check stderr, that keypress will never come.
Some programs, xcopy.exe is a very good example, require stdin to be redirected when you redirect stdout. Although the failure mode for xcopy.exe is an immediate exit without any diagnostic.
Seeing it fixed when you kill your C# program makes the first bullet the likeliest reason.

I know this, it is a very common problem. I has to do with the output, which must be handled asynchronously. You just can't WaitForExit when output exceeds certain amount of data.
You need to add
myStdErr= correctionProcess.StandardError.ReadToEnd();
Only once usually works, if you want to overkill this works ("P" being my Process)
while (!P.HasExited)
stdErr+= P.StandardError.ReadToEnd();

If you don't need the stdout/stderr, just turn the Redirect* properties to false.

Related

Process.Start does not output the full output

I have a process P, which calls the PSEXEC executable, and passes it an argument. My issue is that the output from my C# program is not the same from when I call exactly the same command directly into a command prompt.
Here is the output I expect (when ran from CMD):
Server Name Server Load
-------------------- ------------
601CTXD04 0
601CTXD05 0
...
601CTXP03 0
And here is the actual output (when ran from my program):
Server Name Server Load
-------------------- ------------
601CTXD04 0
So when I run the command from my C# program, I only get 1 server. I call the process the following way :
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = cServer.psexec; //Path to the PSEXEC executable
p.StartInfo.Arguments = "-accepteula \\\\601ctxp01 qfarm /load /continue";
p.Start();
string output = p.StandardOutput.ReadToEnd();
string[] lines = Regex.Split(output, "\\r\\n");
I really do not understand why, the exact same command ran from CMD does not give the same output when ran from a C# process. Please let me know what I am doing wrong as I am currently oblivious to my mistake.
You need to call p.WaitForExit() after p.StandardOutput.ReadToEnd(), otherwise you won't get all of the output from the process. Don't put it directly after p.Start() - you may get a deadlock. See http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput%28v=vs.110%29.aspx
It seems the issue was with PsExec itself (a Sysinternal utility) as I have tried an alternative called PAExec and the same command works fine, so I am using this one in my code instead.
Be sure to have the.
p.WaitForExit()
method after the line where you read the output. Here is an explanation from MSDN: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput(v=vs.110).aspx

Output from py2exe converted program gets received all at once

I have made a python console script, and converted it to a .exe with py2exe (I have used the console = ['test.py'] line in my setup file).
The program parses a file, and during the parse it prints out how much of the file it has parsed. Typical output would be:
Processing (currently at 1%)
Processing (currently at 4%)
etc.
When running the file in a cmd window it works just as expected.
I have also created a very small C# WPF program that just runs the parser:
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"C:\temp\test.exe");
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
Task t = new Task(() =>
{
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
p.Close();
});
t.Start();
The p_OutputDataReceived handler just sends the received output to a textbox. This works and I have tested it on other programs, and there I get the output from the program when I expect.
However when I run my parser (the one created with py2exe) I get all outputs just after the parser has finished. So in the end I get all the correct output, but I get them all at the same time...
(note, I don't get one big output, but rather all the expected outputs but still, all at the same time)
So to be perfectly clear here:
If I run the parser from the command window, I get the outputs one by one
I have tested to run a C# console program instead of the py2exe generated program and that works (I get the outputs one by one)
Python checks if sys.stdout (the program's standard output) is a console. If it is, Python flushes write buffers immediately so the user can see it. Otherwise writes get cached and are outputted all at once:
when the write buffer is full or
at program exit.
The logic behind this is better performance, since when redirecting stdout to a file or to other programs, typically no one cares when the output occurs.
You can fix this by including sys.stdout.flush() in strategic locations in your Python parser script (i.e. directly after printing status line).
Btw: You should be able to observe the same time-delay behavior if you redirect the output of your parser to more, for example:
C:\temp\test.exe | more

Trying to get StandardOutput after running a console process

I can run a console process using the following C# code. The goal is also to collect all the output from such process:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.Arguments = commandLine;
proc.StartInfo.FileName = "signtool.exe";
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
if (proc.WaitForExit(10000))
{
Debug.WriteLine(proc.StandardOutput.ReadToEnd());
}
What I receive is this:
"Done Adding Additional Store\r\n"
But when I do the same from a Windows command line I get this:
Done Adding Additional Store
SignTool Error: File not found: C:\SomeBadFile.exe
Why am I getting only the first line of output with my code?
Seeing as the line you are missing seems like an error message, should you not be looking at Process.StandardError Property
When a Process writes text to its standard error stream, that text is
normally displayed on the console. By redirecting the StandardError
stream, you can manipulate or suppress the error output of a process.
For example, you can filter the text, format it differently, or write
the output to both the console and a designated log file.
Have you tried redirecting and watching StandardError too? It seem likley that this is output to the error stream.

Getting output from one executable in an other one

I'm currently trying to get the output of an executable console-app into an other one. To be exact, a little overview of what I'm trying to do:
I have one executable which I cannot edit and neither see it's code. It writes some (quite a bunch to be honest) lines into the console when executed.
Now I want to write another executable that starts the one above and reads the things it writes.
Seems simple to me, so I started coding but ended up with an error message saying that StandardOut has not been redirected or the process hasn't started yet.
I tried it using this kinda structure (C#):
Process MyApp = Process.Start(#"C:\some\dirs\foo.exe", "someargs");
MyApp.Start();
StreamReader _Out = MyApp.StandardOutput;
string _Line = "";
while ((_Line = _Out.ReadLine()) != null)
Console.WriteLine("Read: " + _Line);
MyApp.Close();
I can open the executable and it also does open the one inside, but as soon as it comes to reading the returned values, the app crashes.
What am I doing wrong?!
Take a look at the documentation for the Process.StandardOutput property. You will need to set a boolean indicating that you want the stream redirected as well as disabling shell execute.
Note from the documentation:
To use StandardOutput, you must set ProcessStartInfo..::.UseShellExecute to false, and you must set ProcessStartInfo..::.RedirectStandardOutput to true. Otherwise, reading from the StandardOutput stream throws an exception
You would need to change your code a little bit to adjust for the changes:
Process myApp = new Process(#"C:\some\dirs\foo.exe", "someargs");
myApp.StartInfo.UseShellExecute = false;
myApp.StartInfo.RedirectStandardOutput = false;
myApp.Start();
string output = myApp.StandardOutput.ReadToEnd();
p.WaitForExit();
you could try setting processStartInfo.RedirectStandardOutput = true;
As noted above, you can use RedirectStandardOutput as here.
Another, dirtier way is something like
using (Process child = Process.Start
("cmd", #"/c C:\some\dirs\foo.exe someargs > somefilename"))
{
exeProcess.WaitForExit();
}
And then read its output from somefilename

c# redirect (pipe) process output to another process

I am trying to run a process in c# using the Process class.
Process p1 = new process();
p1.startinfo.filename = "xyz.exe";
p1.startinfo.arguments = //i am building it based on user's input.
p1.start();
So based on user input i am building the argument value. Now i have a case where i have to pipe the output of p1 to another process say grep. so i basically tried this
p1.startinfo.arguments = "-info |grep 1234" ;
what i intended is something like xyz.exe -info|grep 1234
but this doesn't seem to work in .net .. I can actually create another process variable and run "grep" as a separate process.. But i was wondering if there is any way to do as iam trying out above..
The much easier way would be to do just use cmd as your process.
Process test = new Process();
test.StartInfo.FileName = "cmd";
test.StartInfo.Arguments = #"/C ""echo testing | grep test""";
test.Start();
You can capture the output or whatever else you want like any normal process then. This was just a quick test I built, but it works outputting testing to the console so I would expect this would work for anything else you plan on doing with the piping. If you want the command to stay open then use /K instead of /C and the window will not close once the process finishes.

Categories