Deadlock in System.Diagnostic.Process - c#

I have a small console application and I want to read the output in C#. Therefore I've created this code snippet. The command prompt opens, but nothing is displayed.
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
process.StartInfo.FileName = DirectoryPath + "Test.exe";
process.StartInfo.Arguments = "-showAll";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
process.WaitForExit(2000);
String strOutput = process.StandardOutput.ReadToEnd();
If I remove UseShellExecute, RedirectStandardOutput and the last line, the command prompt opens and the Test.exe is shown, but I need the output as String and so I have to use these attributes to read the StandardOutput
I've also tried to set a timeout of 2 seconds (process.WaitForExit(2000)), but the empty command prompt does not close after 2 seconds.
If I close the empty command prompt manually in debug mode, the variable strOutput has my requested information.

To avoid deadlock you have to read the output stream before you wait to exit. So try :
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
process.StartInfo.FileName = DirectoryPath + "Test.exe";
process.StartInfo.Arguments = "-showAll";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
String strOutput = process.StandardOutput.ReadToEnd();
process.WaitForExit();

Related

How to grab the output percentage of ADB.exe push command process in c#?

I'm creating an app that copy files to android device.
When I run via cmd or powershell, it shows a percentage of copied files, but when using the following code, those not redirect the output.
I try to create a CMD process, an ADB process, powershell, nothing, only shows the output at the end of the precess.
folderToLoad = txtOBBFolder.Text;
process = new Process();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + #"\adb.exe";
process.StartInfo.Arguments = #"push " + folderToLoad + " /sdcard/Android/obb/" + Path.GetFileName(folderToLoad);
process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = false;
process.Start();
q = "";
while (!process.HasExited)
{
q += process.StandardOutput.ReadToEnd();
q += process.StandardError.ReadToEnd();
txtOutput.AppendText(q);
}
Any one as a better way to make this?
If the adb push takes a while, for the user, it seems that the program hang up, thats why I would like to show a progress bar for example, with the percentage that is being sent.

Netsh command not working in C# to capture trace

using (System.Diagnostics.Process process = new System.Diagnostics.Process())
{
process.StartInfo.FileName = "netsh.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
string cmd = "trace start capture=yes";
process.StartInfo.Arguments = cmd;
process.Start();
// Synchronously read the standard output of the spawned process.
StreamReader reader = process.StandardOutput;
output = reader.ReadToEnd();
// Write the redirected output to this application's window.
//Console.WriteLine(output);
process.WaitForExit();
}
The above code gives me following error "The following command was not found: trace start capture=yes"

C# Piping Linux Command Output in Process

I am having trouble with the Process class to pipe a command on a Linux system.
I want to execute the following command: rpm2cpio repo.rpm | cpio -divm
I've tried
process.StartInfo.FileName = "rpm2cpio;
rocess.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.Arguments = "repo.rpm | cpio - idmv";
But the program hangs.
Similarly, I tried saving the output from rpm2cpio to a string or an output file and then pass that as the argument for the cpio command, but it also hangs.
process.StartInfo.FileName = "cpio";
rocess.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.Arguments = "-idvm < output.txt";
// or
process.StartInfo.Arguments = "-idvm < " + rp2cpio_output;
What are some ways I can get this working? I saw this post with a solution, but it is on a Window's system. How do the same thing on Linux?
Setting process.StartInfo.RedirectStandardOutput=true will cause the program to redirect standard output to the stream process.StartInfo.StandardOutput. When this happens the program will hang until you read from standard output.
To get the behavior I think you are looking for, you just need to set RedirectStandardOutput=false. That way the pipes and redirects in your command will work as expected.
Rather than directly writing to a file, you can simply use a StreamWriter to fetch the output in a stream buffer and then use that to write to the file. If the process still hangs, simply use the timeout command of linux to terminate the process.
The following snippet may help after making a few changes:
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.FileName = "/bin/bash";
processStartInfo.WorkingDirectory = "/";
string cmd = "timeout 1 cat > temp.txt";
var escapedArgs = cmd.Replace("\"", "\\\"");
processStartInfo.Arguments = $"-c \"{escapedArgs}\"";
processStartInfo.UseShellExecute = false;
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;
processStartInfo.StandardInputEncoding = System.Text.Encoding.UTF8;
processStartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
processStartInfo.UseShellExecute = false;
process.StartInfo = processStartInfo;
process.Start();
stdIOWriter = process.StandardInput;
stdIOWriter.WriteLine("Hey Fellas");
String error = process.StandardError.ReadToEnd();
String output = process.StandardOutput.ReadToEnd(); ```

Running an exe in C# with commandline parameters, suppressing the dos window

I am using lame for transcoding for one of my project. The issue is that when I call lame from C#, a DOS window pops out. Is there any way I can suppress this?
Here is my code so far:
Process converter =
Process.Start(lameExePath, "-V2 \"" + waveFile + "\" \"" + mp3File + "\"");
converter.WaitForExit();
Did you try something like:
using( var process = new Process() )
{
process.StartInfo.FileName = "...";
process.StartInfo.WorkingDirectory = "...";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.Start();
}
Assuming you are calling it via Process.Start, you can use the overload that takes ProcessStartInfo that has its CreateNoWindow property set to true and its UseShellExecute set to false.
The ProcessStartInfo object can also be accessed via the Process.StartInfo property and can be set there directly before starting the process (easier if you have a small number of properties to setup).
Process bhd = new Process();
bhd.StartInfo.FileName = "NSOMod.exe";
bhd.StartInfo.Arguments = "/mod NSOmod /d";
bhd.StartInfo.CreateNoWindow = true;
bhd.StartInfo.UseShellExecute = false;
Is another way.
This is my code that does a similar thing, (and also reads the output and return code)
process.StartInfo.FileName = toolFilePath;
process.StartInfo.Arguments = parameters;
process.StartInfo.UseShellExecute = false; // needs to be false in order to redirect output
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true; // redirect all 3, as it should be all 3 or none
process.StartInfo.WorkingDirectory = Path.GetDirectoryName(toolFilePath);
process.StartInfo.Domain = domain;
process.StartInfo.UserName = userName;
process.StartInfo.Password = decryptedPassword;
process.Start();
output = process.StandardOutput.ReadToEnd(); // read the output here...
process.WaitForExit(); // ...then wait for exit, as after exit, it can't read the output
returnCode = process.ExitCode;
process.Close(); // once we have read the exit code, can close the process

How to hide cmd window while running a batch file?

How to hide cmd window while running a batch file?
I use the following code to run batch file
process = new Process();
process.StartInfo.FileName = batchFilePath;
process.Start();
If proc.StartInfo.UseShellExecute is false, then you are launching the process and can use:
proc.StartInfo.CreateNoWindow = true;
If proc.StartInfo.UseShellExecute is true, then the OS is launching the process and you have to provide a "hint" to the process via:
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
However the called application may ignore this latter request.
If using UseShellExecute = false, you might want to consider redirecting standard output/error, to capture any logging produced:
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.OutputDataReceived += new DataReceivedEventHandler(ProcessOutputHandler);
proc.StartInfo.RedirectStandardError = true;
proc.ErrorDataReceived += new DataReceivedEventHandler(ProcessOutputHandler);
And have a function like
private void ProcessOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data)) // use the output outLine.Data somehow;
}
There's a good page covering CreateNoWindow this on an MSDN blog.
There is also a bug in Windows which may throw a dialog and defeat CreateNoWindow if you are passing a username/password. For details
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98476
http://support.microsoft.com/?kbid=818858
According to the Process properties, you do have a:
Property: CreateNoWindow
Notes: Allows you to run a command line program silently.
It does not flash a console window.
and:
Property: WindowStyle
Notes: Use this to set windows as hidden.
The author has used ProcessWindowStyle.Hidden often.
As an example!
static void LaunchCommandLineApp()
{
// For the example
const string ex1 = "C:\\";
const string ex2 = "C:\\Dir";
// Use ProcessStartInfo class
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "dcm2jpg.exe";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "-f j -o \"" + ex1 + "\" -z 1.0 -s y " + ex2;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
catch
{
// Log error.
}
}
Use:
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
This is what worked for me,
When you redirect all of the input and output, and set the window hidden it should work
Process p = new Process();
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
try with this and this where the c# code is embedded into the batch files:
#echo off
echo self minimizing
call getCmdPid.bat
call windowMode.bat -pid %errorlevel% -mode minimized
echo --other commands--
pause
Though it might be not so easy to unhide the window.

Categories