.NET standardOut is not getting redirected - c#

I have a part of a code where I need to start up a console application from my .NET console application and get its output and in the best scenario also print that output. But I am getting error:
StandardOut has not been redirected or the process hasn't started yet
I got RedirectStandardOutput set to true and the thread has according to log started (I got "read started" printed out).
I am attaching problematic pieces of the code below. Anyone got an idea where the problem is? I will be grateful for any useful advice.
Thread readingThread = new Thread(Read);
ProcessStartInfo info = new ProcessStartInfo()
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
FileName = "../../" + path + "/server_run.sh",
};
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.FileName = "../../" + path + "/server_run.sh";
using (Process server = Process.Start(info))
{
readingThread.Start(server);
Console.WriteLine("Starting the server");
int serverNumber = serverPaths.FindIndex(x => x == path);
Console.WriteLine(serverNumber);
serverNumbers.Insert(serverNumber, server.Id);
int i = 0;
foreach (int a in serverNumbers)
{
Console.WriteLine("index: " + i + " " + a);
i++;
}
//////////////string ProcessID;
Console.WriteLine(server.Id.ToString()); ////////////////
Console.WriteLine("Server started");
}
readingThread.Join();
private static void Read(object parameter)
{
Console.WriteLine("read started");
Process process = parameter as Process;
process.BeginOutputReadLine();
process.OutputDataReceived += new DataReceivedEventHandler(MyProcOutputHandler);
}
private static void MyProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
// Collect the sort command output.
if (!String.IsNullOrEmpty(outLine.Data))
{
Console.WriteLine(outLine.Data);
}
}

Related

Tracking DISM progress using C# - Working in Windows 10 but not in WinPE

I am using C# to start DISM process to capture/apply image and to track the progress.
When I run the code on Windows 10 the progress is being updated normally but when the code I run the code inside WinPE environment the progress is not updated but the process is still running normally.
This is the code that triggers the method to start DISM.
Just to note it is running on .NET Framework 4.0
Task T = Task.Factory.StartNew(() =>
{
ApplyImage(machineName, imageIndex, imageDescription);
//Utilities.BailOut();
});
This is the code that I am using to start DISM, Arguments change depending on the needs.
public void ApplyImage(string imageName, int imageIndex)
{
string _imageName = imageName;
int _index = imageIndex;
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo
{
UseShellExecute = true,
CreateNoWindow = true,
RedirectStandardOutput = true,
FileName = "Dism.exe",
Arguments = $#"/apply-image /imagefile:{OS_Deploy}\{_imageName} /index:{_index} /applydir:{TargetDisk}"
};
startInfo.UseShellExecute = false;
process.StartInfo = startInfo;
process.OutputDataReceived += (sender, e) => setLabelText(lblProgress, e.Data);
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
process.CancelOutputRead();
process.Close();
}
And this is the code that is setting the label text
private void setLabelText(Label label, string text)
{
if (label.InvokeRequired)
{
label.Invoke((System.Action)(() => setLabelText(label, text)));
}
else
{
try
{
if (text.Contains("%"))
{
label.Text = "Status : " + text.Split('%')[0].Substring(text.Split('%')[0].Length - 4, 4) + "%";
}
else if (text == "The operation completed successfully.")
{
label.Text = "Completed!";
}
else
{
label.Text = text;
}
}
catch (Exception) { }
}
}
What could be causing this issue and what can I to fix it or maybe create a workaround?

How to redirect the output from the console?

I'm currently trying to read the outputstream from an external console application.
I can not modify this application.
This is to code i'm currently using:
Process process = new Process();
string dir = Directory.GetCurrentDirectory();
process.StartInfo.FileName = dir + "/volibot.exe";
process.StartInfo.UseShellExecute = false;
process.Start();
//do some stuff with the stream
I use this to read the outputstream:
while (!process.StandardOutput.EndOfStream)
{
string message = process.StandardOutput.ReadLine();
Console.WriteLine(message);
}
But whenever I add:
process.StartInfo.RedirectStandardOutput = true;
I get this error:
Unhandled exception: System.IO.IOException: The handle is invalid.
bij System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
bij System.IO.__Error.WinIOError()
bij System.Console.SetWindowSize(Int32 width, Int32 height)
bij RitoBot.Core.Main(String[] args)
This doesn't make sense because this is a console application?
How can I fix this problem?
Or is there a simple work around?
Edit:
Tried this: ProcessInfo and RedirectStandardOutput
static void Main(string[] args)
{
//C:\\Users\\pc\\Documents\\Visual Studio 2013\\Projects\\ConsoleApplication1\\ConsoleApplication1\\bin\\Debug\\VoliBot.exe
Process build = new Process();
build.StartInfo.WorkingDirectory = #"C:\\Users\\pc\\Documents\\Visual Studio 2013\\Projects\\ConsoleApplication1\\ConsoleApplication1\\bin\\Debug\\";
build.StartInfo.Arguments = "";
build.StartInfo.FileName = "volibot.exe";
build.StartInfo.UseShellExecute = false;
build.StartInfo.RedirectStandardOutput = true;
build.StartInfo.RedirectStandardError = true;
build.StartInfo.CreateNoWindow = true;
build.ErrorDataReceived += build_ErrorDataReceived;
build.OutputDataReceived += build_ErrorDataReceived;
build.EnableRaisingEvents = true;
build.Start();
build.BeginOutputReadLine();
build.BeginErrorReadLine();
build.WaitForExit();
Console.ReadLine();
}
static void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
string strMessage = e.Data;
Console.WriteLine(strMessage);
}
Still didnt work :s
Try something like:
var psi = new ProcessStartInfo(#"c:\temp\mycommand.exe", String.Format(" \"{0}\" \"{1}\" \"{2}\"", sourceDoc, dataSource, outputFile))
{
WorkingDirectory = Environment.CurrentDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = false
};
using (var process = new Process { StartInfo = psi })
{
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
// wait for the process to exit
process.WaitForExit();
if (process.ExitCode != 0)
{
}
}
}
You have #"C:\Users\pc\Documents...."
you don't need double \ when you use the # sign..
maybe it is that?

How to run new process after the old process finish, without hang the application

I working on Visual Studio 2010, C# (.Net 4).
I have an application that contain a DataGridView with two columns. Each column contain argument for the program I want to run.
Now I want to run from my C# application another application with parameters from the data grid view.
In additional, I want to wait 3 seconds before running new process.
I try the follow code, but the process runs parallelly and not one after one:
private static Mutex mut = new Mutex();
public void runProgram(string executablePath, string argu1, string argu2)
{
mut.WaitOne();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = Path.GetDirectoryName(executablePath);
startInfo.FileName = "CMD.exe";
startInfo.Arguments = "/C " + set.ExecutablePath + " "
+ argu1 + " " + argu2;
try
{
Process p = Process.Start(startInfo);
//p.WaitForExit(); // don't start the next process until the first finish -> not good, stuck the app
}
catch
{
MessageBox.Show("ERROR: unsuccess to run the applicition");
}
mut.ReleaseMutex();
}
private void bu_RunProgram_Click(object sender, EventArgs e)
{
if (!File.Exists(set.ExecutablePath))
{
MessageBox.Show("The executable file doesn't exist\nPlease select right executable file in the settings form", "Error");
return;
}
int progRow;
foreach (DataGridViewRow dgvr in dg_ParametersToRun.Rows)
{
progRow = dgvr.Index;
string argu1 = dg_ParametersToRun.Rows[progRow].Cells[0].FormattedValue.ToString();
string argu2 = dg_ParametersToRun.Rows[progRow].Cells[1].FormattedValue.ToString();
Thread threadProgRun= new Thread(() => runProgram(set.ExecutablePath, argu1, argu2));
threadProgRun.Start();
Thread.Sleep(3000); // Need to come to this line only when the previous thread finish...
}
}
To be honest, I've never worked with threads..
Thank you!
UPDATE CODE (According the suggestion):
// Aid variable
int paramRowIndex;
public void runNextParameters(object sender, EventArgs e)
{
paramRowIndex++;
if (paramRowIndex > dg_RunListTests.Rows.Count) return; finish run all parameters
//run the test
string argu1 = dg_RunListTests.Rows[paramRowIndex].Cells[0].FormattedValue.ToString();
string argu2 = dg_RunListTests.Rows[paramRowIndex].Cells[1].FormattedValue.ToString();
runParameters(set.ExecutablePath, componenet, test);
}
public void runParameters(string executablePath, string argu1, string argu2)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = Path.GetDirectoryName(executablePath);
startInfo.FileName = "CMD.exe";
startInfo.Arguments = "/C " + set.ExecutablePath + " "
+ argu1 + " " + argu2;
try
{
Process p = Process.Start(startInfo);
p.Exited += runNextParameters;
}
catch
{
MessageBox.Show("Unsuccess to run the test again");
}
}
private void bu_RunParameters_Click(object sender, EventArgs e)
{
if (!File.Exists(set.ExecutablePath))
{
MessageBox.Show("The executable file doesn't exist\nPlease select right executable file in the settings form", Error);
return;
}
paramRowIndex = 0;
runNextParameters(sender, e);
}
Possible fast solution: start a .bat file that starts the two(three) programs. You have to create another program that waits 3 seconds to call in between.

Windows Form Application with Console Application

I have a console application that asks for a SourcePath when started.. when I enter the Source Path, It asks for DestinationPath... when i enter DestinationPath it starts some execution
My Problem is to Supply these path via a windows application, means i need to create a window form application that will supply these parameters to the console application automatiocally after certain time interval
can it be achieved or not... if yes, plese help... its very Urgent...
ohh..
I have tried a lot of code that i can not paste hear all but some that i use to start the application are...
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = #"C:\Program Files\Wondershare\PPT2Flash SDK\ppt2flash.exe";
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardInput = true;
psi.CreateNoWindow = false;
psi.Arguments = input + ";" + output;
Process p = Process.Start(psi);
and
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
FileName = #"C:\Program Files\Wondershare\PPT2Flash SDK\ppt2flash.exe",
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
}
};
if (process.Start())
{
Redirect(process.StandardError, text);
Redirect(process.StandardOutput, text);
MessageBox.Show(text);
}
private void Redirect(StreamReader input, string output)
{
new Thread(a =>{var buffer = new char[1];
while (input.Read(buffer, 0, 1) > 0)
{
output += new string(buffer);
};
}).Start();
}
but nothing seems to be working
You can add parameters to your ProcessStartInfo like this:
ProcessStartInfo psi = new ProcessStartInfo(#"C:\MyConsoleApp.exe",
#"C:\MyLocationAsFirstParamter C:\MyOtherLocationAsSecondParameter");
Process p = Process.Start(psi);
this will startup the console app with 2 parameters.
Now in your console app you have the
static void Main(string[] args)
the string array args is what contains the parameters, now all you have to do is get them when your app starts.
if (args == null || args.Length < 2)
{
//the arguments are not passed correctly, or not at all
}
else
{
try
{
yourFirstVariable = args[0];
yourSecondVariable = args[1];
}
catch(Exception e)
{
Console.WriteLine("Something went wrong with setting the variables.")
Console.WriteLine(e.Message);
}
}
This may or may not be the exact code that you need, but at least will give you an insight in how to accomplish what you want.

Getting command line output dynamically

I'm running a program using command line in c# this program produce some logs while its running in need to display this logs whenever it get change. I wrote the following code but it shows all the logs once the process has been killed and during the running time my program is not responding. how can I fix it?
regards
ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + "C:\\server.py");
Process proc = new Process();
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
procStartInfo.UseShellExecute = false;
procStartInfo.RedirectStandardOutput = true;
//procStartInfo.CreateNoWindow = true;
proc.StartInfo = procStartInfo;
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(300);
LogstextBox.Text = output;
Edited:
well, I tried to use OutputDataReceived but it doesn't show any result, here is the changed code:
{
//processCaller.FileName = #"ping";
//processCaller.Arguments = "4.2.2.4 -t"; this is working
processCaller.FileName = #"cmd.exe";
processCaller.Arguments = "/c c:\\server.py"; //this is not working
processCaller.StdErrReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.StdOutReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.Completed += new EventHandler(processCompletedOrCanceled);
processCaller.Cancelled += new EventHandler(processCompletedOrCanceled);
this.richTextBox1.Text = "Server Started.." + Environment.NewLine;
processCaller.Start();
}
private void writeStreamInfo(object sender, DataReceivedEventArgs e)
{
this.richTextBox1.AppendText(e.Text + Environment.NewLine);
}
This is the problem:
string output = proc.StandardOutput.ReadToEnd();
You won't get to the "end" of standard output until the process has terminated.
You should be reading a line at a time - or possibly just subscribing to the OutputDataReceived event (and following the documented other requirements for that event).
EDIT: Here's sample code which works for me:
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
public static void Main()
{
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/c " + "type Test.cs")
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process process = Process.Start(startInfo);
process.OutputDataReceived += (sender, e) => Console.WriteLine(e.Data);
process.BeginOutputReadLine();
process.WaitForExit();
// We may not have received all the events yet!
Thread.Sleep(5000);
}
}
Note that in your sample code, you're accessing the UI on whatever thread the OutputDataReceived handler is called - that looks like a bad idea to me.
You can use the Process.BeginOutputReadLine Method. The link shows a complete working example in C# which uses the OutputDataReceived event. That code example should do what you want.

Categories

Resources