Why is manual Thread.Sleeping necessary before Process.Start here? - c#

I have a scenario where I am reading a file on an android phone from a C# application by using adb.exe to get in to the phone's shell and reading the file by using a Process in the C# app. However, I need to use Thread.Sleep right before Process.Start here if I want it to actually work. Any ideas why?
Here is the code:
ProcessStartInfo cmdInfo;
string resulterr = "";
string result = "";
cmdInfo = new ProcessStartInfo(" adb.exe ", "shell cat /etc/bluetooth/bt_stack.conf");
cmdInfo.CreateNoWindow = true;
cmdInfo.RedirectStandardOutput = true;
cmdInfo.RedirectStandardError = true;
cmdInfo.UseShellExecute = false;
Process cmd = new Process();
cmd.StartInfo = cmdInfo;
var output = new StringBuilder();
var error = new StringBuilder();
cmd.OutputDataReceived += (o, ef) => output.Append(ef.Data);
cmd.ErrorDataReceived += (o, ef) => error.Append(ef.Data);
//if I don`t have this Thread.Sleep, the error string is "device not found"!!
Thread.Sleep(5000);
cmd.Start();
cmd.BeginOutputReadLine();
cmd.BeginErrorReadLine();
cmd.WaitForExit();
cmd.Close();
resulterr = error.ToString();
result = output.ToString();
cmd.Dispose();
Any ideas why this works with the thread sleeping but doesn`t work without it?? I can run
shell cat /etc/bluetooth/bt_stack.conf
from the command line ad naseaum with no delays and no issues -- why do I need them here??

Ok, in my case the device was actually not ready to receive the commands. I waited for a good device status like this.
ProcessStartInfo lcmdInfo1;
lcmdInfo1 = new ProcessStartInfo(" adb.exe ", "get-state");
lcmdInfo1.CreateNoWindow = true;
lcmdInfo1.RedirectStandardOutput = true;
lcmdInfo1.RedirectStandardError = true;
lcmdInfo1.UseShellExecute = false;
Process cmd2 = new Process();
cmd2.StartInfo = lcmdInfo1;
var output = new StringBuilder();
var error = new StringBuilder();
cmd2.OutputDataReceived += (o, ef) => output.Append(ef.Data);
cmd2.ErrorDataReceived += (o, ef) => error.Append(ef.Data);
cmd2.Start();
cmd2.BeginOutputReadLine();
cmd2.BeginErrorReadLine();
cmd2.WaitForExit();
cmd2.Close();
lresulterr1 = error.ToString();
lresult1 = output.ToString();
cmd2.Dispose();
//sometimes there is an issue with a previously issued command that causes the device status to be 'Unknown'. Wait until the device status is 'device'
while (!lresult1.Contains("device"))
{
lcmdInfo1 = new ProcessStartInfo(" adb.exe ", "get-state");
lcmdInfo1.CreateNoWindow = true;
lcmdInfo1.RedirectStandardOutput = true;
lcmdInfo1.RedirectStandardError = true;
lcmdInfo1.UseShellExecute = false;
cmd2 = new Process();
cmd2.StartInfo = lcmdInfo1;
output = new StringBuilder();
error = new StringBuilder();
cmd2.OutputDataReceived += (o, ef) => output.Append(ef.Data);
cmd2.ErrorDataReceived += (o, ef) => error.Append(ef.Data);
cmd2.Start();
cmd2.BeginOutputReadLine();
cmd2.BeginErrorReadLine();
cmd2.WaitForExit();
cmd2.Close();
lresulterr1 = error.ToString();
lresult1 = output.ToString();
cmd2.Dispose();
}
//now your device is ready. Go ahead and fire off the shell commands

Related

How to redirect input and output of existing process c#

There are two endpoints, I am thinking to add one endpoint to start the process and another is to do process communication(stdin/stdin). Is it possible? Or should I use some other ways to do this like websocket?
I am trying to start a process as below.
Process process = new Process();
ProcessStartInfo procStartInfo = new ProcessStartInfo("/bin/sh");
procStartInfo.RedirectStandardError = true;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardInput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.Arguments = "-c " + Constants.CMDName + args;
process.StartInfo = procStartInfo;
Console.WriteLine("Start res: " + process.Start());
Process is getting started but when I am trying to do stdin/out like below I am getting an error saying StandardIn not redirected.
Process[] processes = Process.GetProcessesByName(Constants.VSDebugProcessName);
if (processes.Length == 0)
{
throw new Exception("Process is not running");
}
Console.WriteLine(JsonSerializer.Serialize(processes[0].StartInfo));
var process = processes[0];
StreamWriter sw = process.StandardInput;
await sw.WriteLineAsync(JsonSerializer.Serialize(payload));
Should I combine these two endpoints or is there any other workaround for this issue?
You can set EnableRaisingEvents = true in the ProcessStartInfo, and add a handler on the process’s OutputDataReceived message to collect the output. The following snippet illustrates the procedure. It also handles error output (stderr).
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
},
EnableRaisingEvents = true,
};
var output = new StringBuilder();
var error = new StringBuilder();
process.OutputDataReceived += (_, args) =>
{
output.AppendLine(args.Data);
};
process.ErrorDataReceived += (_, args) =>
{
error.AppendLine(args.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
ResultsText.Value = output.ToString();

c# - How to asynchronously stream output from ffmpeg

I created a method to call ffmpeg binaries and do stuff for me. It worked perfectly fine on a standard console application. I am trying to make a Windows Form Application version but there are few problems. The app freezes (but the progress bar is still updating) when the ffmpeg process is still running. The textboxes are not being updated. I cannot move the app window. I suspect this is because of the loop and I googled some stuff and found out that I might need to do this asynchronously but how do I do that exactly.
public void ffmpeg(string ffmpeg_exe, string args)
{
Process p = new Process();
p.StartInfo.FileName = ffmpeg_exe;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
p.Start();
StreamReader reader = p.StandardError;
string line;
string size = "", current_duration = "", duration = "";
while ((line = reader.ReadLine()) != null)
{
if (!string.IsNullOrEmpty(line))
{
if (line.Contains("Duration") && line.Contains("bitrate") && line.Contains("start"))
{
duration = RemoveWhitespace(Between(line, "Duration:", ", start"));
totaltime.Text = duration;
}
if (line.Contains("frame=") && line.Contains("size=") && line.Contains("time="))
{
size = RemoveWhitespace(Between(line, "size=", " time"));
current_duration = RemoveWhitespace(Between(line, "time=", " bitrate"));
progressBar_main.Value = Convert.ToInt32(Math.Round(TimeSpan.Parse(current_duration.Substring(0, current_duration.Length -3)).TotalSeconds * 100 / TimeSpan.Parse(duration.Substring(0,duration.Length-3)).TotalSeconds, 3));
current_time.Text = current_duration;
filesize.Text = size;
}
}
}
p.Close();
current_time.Text = "";
filesize.Text = "";
totaltime.Text = "";
progressBar_main.Value = 0;
}
Try using Task like this :
Action action = () =>
{
//Do your streaming here
};
Then start it :
Task t2 = Task.Factory.StartNew(action);
Hope this was useful.

execute multi-line cmd command in c#

I am creating java compiler in c# .it is working perfect if there is no input.but it ask forstrong text input it give me error (Exception in thread "main" java.util.NoSuchElementException: No line found)
public void executeit()
{
adresss = "";
string dir = textBox1.Text;
adresss = dir;
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
info.CreateNoWindow = true;
string[] s = new string[30];
s = Directory.GetDirectories(#"C:\Program Files\Java\", "jdk1*");
info.WorkingDirectory = s[0] + #"\bin\";
info.Arguments = "/c javac " + "\"" + dir + "\"";
Process p = new Process();
info.UseShellExecute = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
label1.Text = "";
p.StartInfo = info;
p.Start();
StreamReader sw = p.StandardError;
string err = sw.ReadToEnd();
label1.Text = err;
if (label1.Text == "")
{
label1.Text = "Compiled without Errors";
}
}
and it is java file:
import java.util.Scanner;
public class inputtry {
public static void main (String args[]){
Scanner reader = new Scanner(System.in);
System.out.println("Enter the first number");
//get user input for a
String a=reader.nextLine();
System.out.print("number is:");
System.out.print(a);
}
}

C# executing cmd command not working

Can anybody suggest why the following code not returning system date?
ProcessStartInfo cmdInfo = new ProcessStartInfo("cmd.exe", "net time \\192.168.221.1");
cmdInfo.CreateNoWindow = true;
cmdInfo.RedirectStandardOutput = true;
cmdInfo.RedirectStandardError = true;
cmdInfo.UseShellExecute = false;
Process cmd = new Process();
cmd.StartInfo = cmdInfo;
var output = new StringBuilder();
var error = new StringBuilder();
cmd.OutputDataReceived += (o, e) => output.Append(e.Data);
cmd.ErrorDataReceived += (o, e) => error.Append(e.Data);
cmd.Start();
cmd.BeginOutputReadLine();
cmd.BeginErrorReadLine();
cmd.WaitForExit();
cmd.Close();
var s = output;
var d = error;
Output is
{Microsoft Windows [Version 6.1.7601]Copyright (c) 2009 Microsoft Corporation. All rights reserved.D:\TEST\TEST\bin\Debug>}
Try with this
ProcessStartInfo cmdInfo = new ProcessStartInfo("cmd.exe", "/C net time \\\\192.168.221.1");
You need to add the /C switch to catch the output of running command inside the CMD shell.
Also the backslash should be doubled or use the string Verbatim prefix #

Pipes between C# and Delphi, How to make it work?

I have a console application (Host.exe) that is written in Delphi. It accepts stdin readln and responses to stdout by writeln.
Now, I want to use Host.exe in C# application in a way that C# gives input to Host.exe and gets the output from Host.exe
Ideally, I write the code below but it doesn't work: it hangs somewhere in the outputReader.ReadLine();
System.IO.File.WriteAllText(tmp, vbs);
Process pProcess = new Process();
pProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
//strCommand is path and file name of command to run
pProcess.StartInfo.FileName = #"Host.exe";
pProcess.StartInfo.Arguments = "\"runa " + tmp +"\"";
// runs script file tmp in background
pProcess.StartInfo.CreateNoWindow = true;
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.StartInfo.RedirectStandardInput = true;
pProcess.StartInfo.RedirectStandardError = true;
pProcess.Start();
StreamWriter inputWriter = pProcess.StandardInput;
StreamReader outputReader = pProcess.StandardOutput;
while (true)
{
inputWriter.WriteLine("getmsg");
inputWriter.Flush();
string s = outputReader.ReadLine(); // then do something with it
inputWriter.WriteLine("progressglobal");
inputWriter.Flush();
string p = outputReader.ReadLine();
if (p == "100")
{
break;
}
Application.DoEvents();
Thread.Sleep(1000);
}
inputWriter.WriteLine("exit");
inputWriter.Flush();
pProcess.WaitForExit();
Many thanks for any suggestions in advance !
You read the line twice:
string s = outputReader.ReadLine();
and
string p = outputReader.ReadLine();
It seems you only need the last line as the variable s is not used.

Categories

Resources