Getting GCC's output from command line when running it through C# - c#

I'm currently compiling a C program through my C# app. If gcc outputs anything it means that there was an error. I want to retrieve this error and display it to the user.
Currently, I'm doing this...
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = _cCompilerPath,
Arguments = " ./file.c",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
string message = string.Empty;
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
message = string.Concat(message, line);
}
MessageBox.Show("OUTPUT :" + message);
But even when there is an error in the program, nothing gets redirected to the Standard Output, and the EndOfStream always returns true.

I would bet that it's writing to StandardError instead.
RedirectStandardError = true,
....
while (!proc.StandardError.EndOfStream)
{
string line = proc.StandardError.ReadLine();
message = string.Concat(message, line);
}

Use Console.WriteLine("message"); if you are working with the console. The MessageBox is for WinForms applications.
Console.WriteLine("OUTPUT: {0}", message);
Console.WriteLine writes to the standard output.

Related

CMD commands won't return an output C# .net

I'm currently having an issue where I'm trying to get the output of the command "arp -a" from CMD in my C# .net program
Process p = null;
string output = string.Empty;
try
{
p = Process.Start(new ProcessStartInfo("arp", "-a")
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true
});
output = p.StandardOutput.ReadToEnd();
Console.WriteLine(output);
p.Close();
}
catch(Exception e)
{
throw new Exception("Error", e);
}
I expect to get some sort of string value in the "output" variable, but all I get is a blank "". I did test if it worked in the first place by changing it to
p = Process.Start(new ProcessStartInfo("ipconfig")
and my "output" variable was filled with what you would expect if you typed in ipconfig into CMD, so i know it worked.
any ideas?

Getting the error of a Powershell Script within c# and outputting it with conditional statement?

I have a console application and a method that executes a PowerShell script within the console application. So I'm trying to grab an error text that it outputs in the application and do something with it.
Example/What I'm trying to do:
If Error.contains("Object")
{
// do something here
}
Here is my current method
public void ExecutePowershellScript()
{
var file = #"C:\Path\filename.ps1";
var start = new ProcessStartInfo()
{
FileName = "powershell.exe",
Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{file}\"",
UseShellExecute = false
};
Process.Start(start);
}
Process.start: how to get the output?
When you create your Process object set StartInfo appropriately:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "program.exe",
Arguments = "command line arguments to your executable",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
then start the process and read from it:
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
// do something with line
}
You can use int.Parse() or int.TryParse() to convert the strings to numeric values. You may have to do some string manipulation first if there are invalid numeric characters in the strings you read.
You can set RedirectStandardError = true and access any errors from process.StandardError
public static void ExecutePowershellScript()
{
var file = #"C:\Path\filename.ps1";
var start = new ProcessStartInfo()
{
FileName = "powershell.exe",
Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{file}\"",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
using Process process = Process.Start(start);
string output = process.StandardOutput.ReadToEnd();
string errors = process.StandardError.ReadToEnd();
}
Okay, scratch the above suggestion.
After being corrected by mklement0,
This is a perfectly reasonable attempt, but, unfortunately, it can lead to hangs (while waiting for one's stream end, the other, when exceeding the buffer size, may cause process execution to block). If you need to capture both streams, you must collect the output from one of them via events. – mklement0
I changed the solution to use the ErrorDataReceived event
public static async Task ExecutePowershellScript()
{
var file = #"C:\Path\filename.ps1";
var start = new ProcessStartInfo
{
FileName = "powershell.exe",
Arguments = $"-NoProfile -ExecutionPolicy unrestricted -file \"{file}\"",
UseShellExecute = false,
// redirect standard error stream to process.StandardError
RedirectStandardError = true
};
using var process = new Process
{
StartInfo = start
};
// Subscribe to ErrorDataReceived event
process.ErrorDataReceived += (sender, e) =>
{
// code to process the error lines in e.Data
};
process.Start();
// Necessary to start redirecting errors to StandardError
process.BeginErrorReadLine();
// Wait for process to exit
await process.WaitForExitAsync();
}
start.Start();
while (!start.StandardOutput.EndOfStream)
{
string line = start.StandardOutput.ReadLine();
}

Get Values from Process StandardOutput

I am attempting to get output to show the currently open documents on my machine, but it comes back NULL no matter what.
StringCollection values = new StringCollection();
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "openfiles.exe",
Arguments = "/query /FO CSV /v",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
values.Add(line);
}
foreach (string sline in values)
MessageBox.Show(sline);
Edit:
During further review I see that I am getting an exception issue. During my diag run I get the following:
Proc.BasePriority thre an exception of type System.InvalidOperationException
Edit:
Attempted to pull code as:
string val = proc.StandardOutput.ReadToEnd();
MessageBox.Show(val);
Also a NULL value on return, and Proc still had errors even after proc.start();.
You have to read both the standard output and standard error streams. This is because you can't read them both from the same thread.
To achieve this you have to use the eventhandlers that will be called on a separate thread.
Compile the code as anycpu as openfiles comes in a 32-bit and 64-bit variant. It might not find the executable if there is an architecture mismatch.
The lines that are read from the error stream are prepended with ! > so they stand out in the output.
StringCollection values = new StringCollection();
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "openfiles.exe",
Arguments = "/query /FO CSV /v",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = false
}
};
proc.Start();
proc.OutputDataReceived += (s,e) => {
lock (values)
{
values.Add(e.Data);
}
};
proc.ErrorDataReceived += (s,e) => {
lock (values)
{
values.Add("! > " + e.Data);
}
};
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
foreach (string sline in values)
MessageBox.Show(sline);

Process with ProcessWindowStyle.Hidden still shows Press any key to exit?

I have this:
var startInfo = new ProcessStartInfo
{
FileName = _pathToExe,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
WorkingDirectory = FilepathHelper.GetFolderFromFullPath(_pathToExe),
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
try
{
using (_proc = Process.Start(startInfo))
{
_proc.EnableRaisingEvents = true;
_proc.ErrorDataReceived += proc_DataReceived;
_proc.OutputDataReceived += proc_DataReceived;
_proc.BeginErrorReadLine();
_proc.BeginOutputReadLine();
var myStreamWriter = _proc.StandardInput;
var allArgs = "";
foreach (var arg in _args)
allArgs += arg + Environment.NewLine;
myStreamWriter.Write(allArgs);
_proc.WaitForExit();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
And I am executing an *.exe that someone else wrote. For this particular *.exe - even though you can clearly see above that I have set ProcessWindowStyle.Hidden, I still see a black window appear with the words "Press any key to exit.". This *.exe - if I run from the command line (instead of calling it from my C# code) produces a tremendous amount of console output text. I do not see this output text when I run my C# code, which is what I want and also means the redirection is working.
I checked and the process is finished - it's as if the command window itself is adding this extra (undesirable) step.
Has anyone encountered this before and if so how can I get rid of this?
It seems that the program you are starting is calling system("PAUSE") at the end thus spawning a new process which prints the "Press Any Key to Continue..." message and waits for user input. I cannot reproduce the exact situation of yours but you can try this.
var startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true,
};
try
{
Process _proc;
using (_proc = Process.Start(startInfo))
{
_proc.EnableRaisingEvents = true;
_proc.BeginErrorReadLine();
_proc.BeginOutputReadLine();
var myStreamWriter = _proc.StandardInput;
myStreamWriter.WriteLine("D:\\your.exe"); //write your.exe to cmd and press enter :)
_proc.WaitForExit();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
From Document:
To use System.Diagnostics.ProcessWindowStyle.Hidden, the system.Diagnostics.ProcessStartInfo.UseShellExecute property must be true.

Is there a way to create a second console to output to in .NET when writing a console application?

Is there a way to create a second console to output to in .NET when writing a console application?
Well, you could start a new cmd.exe process and use stdio and stdout to send and recieve data.
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe")
{
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false
};
Process p = Process.Start(psi);
StreamWriter sw = p.StandardInput;
StreamReader sr = p.StandardOutput;
sw.WriteLine("Hello world!");
sr.Close();
More info on MSDN.
The following fires off an application-dependent number of console windows and stores the amount and parameters for the console inside a String Dictionary that is then looped to generate the required amount of spawned console apps. You would only need the process stuff if only spawning one of course.
//Start looping dic recs and firing console
foreach (DictionaryEntry tests in steps)
{
try
{
Process runCmd = new Process();
runCmd.StartInfo.FileName = CONSOLE_NAME;
runCmd.StartInfo.UseShellExecute = true;
runCmd.StartInfo.RedirectStandardOutput = false;
runCmd.StartInfo.Arguments = tests.Value.ToString();
if (cbShowConsole.Checked)
{
runCmd.StartInfo.CreateNoWindow = true;
runCmd.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
}
else
{
runCmd.StartInfo.CreateNoWindow = false;
runCmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
}
runCmd.Start();
}
catch (Exception ex)
{
string t1 = ex.Message;
}
}
Note this is intended either to run hidden (CreateNoWindow) or visible.
A single console is attached to any given process. So in short you can not. But there are ways to "fake it"

Categories

Resources