I'm using a commandline execute to run a reg delete /f. Now when I do it via commandline it works as intended, but if I run it from C# I still get a prompt.
Now I'm wondering where the erorr lies....thus why do I still get a prompt when I call the command via C# despite the /f parameter being used.
Edit: A small info here: .NET Framework is 3.5
The code that is being used is as follows:
LaunchProcessAndWait(#"cmd",
#"/c reg delete " + "\""
+ #"HKLM\Software\Policies\Microsoft\Internet Explorer\Main"+ "\""
+ #" /v DisableFirstRunCustomize /f",
"");
public static string LaunchProcessAndWaitForOutput(string commandline, string args, bool returnError, bool returnOutput, string workingDir)
{
ProcessStartInfo info = new ProcessStartInfo(commandline, args);
if (workingDir != null)
{
info.WorkingDirectory = workingDir;
}
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.CreateNoWindow = true;
Process p = Process.Start(info);
string outStr = "";
string errStr = "";
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
outStr += e.Data + "\r\n";
});
p.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
{
errStr += e.Data + "\r\n";
});
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
p.Close();
return "" + (returnOutput ? outStr : "") + (returnError ? errStr : "");
}
}
Hi all i am trying to print a pdf file. For this i have created a windows form application. My application print the pdf if i use the default printer of the system. But problem is that when i try to print the PDF file with selected printer from dropdown my code does not works.
private bool SendToPrinter(string filePath, string filename)
{
bool Status = false;
string PrinterName;
string PaperName;
PrinterName = "";
try
{
PrinterName = Convert.ToString(cmbPrinterList.SelectedItem);
// Set the printer.
AddPrinterConnection(PrinterName);
SetDefaultPrinter(PrinterName);
//Print the file with number of copies sent.
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.Arguments = "\"" + PrinterName + "\"";
info.FileName = #filePath + #"\" + filename;
info.CreateNoWindow = false;
info.WindowStyle = ProcessWindowStyle.Hidden;
info.UseShellExecute = true;
Process p = new Process();
p.StartInfo = info;
p.Start();
p.WaitForInputIdle();
System.Threading.Thread.Sleep(2);
if (false == p.CloseMainWindow())
p.Kill();
Status = true;
}
catch (Exception ex)
{
}
return Status;
}
//Set the added printer as default printer.
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetDefaultPrinter(string Name);
//Add the printer connection for specified pName.
[DllImport("winspool.drv")]
public static extern bool AddPrinterConnection(string pName);
public bool viewTabOrder = true;
Try the below code
This is working with different printers for me. Hope it will help you too :)
public void SendToPrinter(string filePath, string Printer)
{
try
{
Process proc = new Process();
proc.Refresh();
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.Verb = "printto";
proc.StartInfo.FileName = ConfigurationManager.AppSettings["ReaderPath"].ToString();
proc.StartInfo.Arguments = String.Format("/t \"{0}\" \"{1}\"", filePath, Printer);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
if (proc.HasExited == false)
{
proc.WaitForExit(20000);
}
proc.EnableRaisingEvents = true;
proc.Close();
}
catch (Exception e)
{
}
}
Code to bind the Printers into dropdownlist.
cmbPrinter.Items.Insert(0, "--Select Printer--");
for (int i = 0; i < PrinterSettings.InstalledPrinters.Count; i++)
{
var pkInstalledPrinters = PrinterSettings.InstalledPrinters[i];
cmbPrinter.Items.Insert(i + 1, pkInstalledPrinters);
}
And Pass the parameter as below
SendToPrinter(FilePath,cmbPrinter.SelectedItem.ToString());
I'm using Mplayer to extrac audio from video via command line. This is the command i use:
mplayer -ao pcm:fast:file=aaa.wav aaa.avi
I copied Mplayer.exe and aaa.avi both on windows drive (C:) and on the root directory of an external hard drive (in my case X).
When i execute from C the dumping start at normal speed (i see the video on real time) and aaa.wav is not created by Mplayer.
When i execute form X the dumping start at fast speed (as requested by the -ao pcm:fast audio driver) and the aaa.wav is correctly created.
I have the same issue in my app, here the code i use to do it:
public static string DumpWav_ConsoleOutput = "";
public static int DumpWav_ProcessID = 0;
Process DumpWav_Process = null;
private void DumpWav(string SourceFileName, string DestinationFileName, bool NeedToCut, TimeSpan Start, TimeSpan End)
{
//cancelliamo le variabili
DumpWav_ConsoleOutput = "";
//Handle della finestra di Media Player
Variables.MediaPlayerHandle = 0;
Variables.MediaPlayerHandle = (int)MediaPlayer.Handle;
Thread thread = new Thread(() => _DumpWav(SourceFileName, DestinationFileName, NeedToCut,Start, End)); //il thread principale di Dump Wav
thread.Start();
while (thread.IsAlive) //aspettiamo il suo completamento
{
Application.DoEvents();
}
var myForm = new Output();
myForm.SetOutputText = Variables.ConsoleOutputMP;
myForm.Show();
Variables.MediaPlayerExit = true;
// ok il processo è terminato
}
private void _DumpWav(string SourceFileName, string DestinationFileName, bool NeedToCut, TimeSpan Start, TimeSpan End)
{
string Output;
Output = RunDumpWav((output) => { }, SourceFileName, DestinationFileName, NeedToCut, Start, End);
}
// Media Player avviato da questa funzione
public string RunDumpWav(Action<string> output, string SourceFileName, string DestinationFileName, bool NeedToCut, TimeSpan Start, TimeSpan End)
{
if (output == null)
throw new ArgumentNullException("output");
string args;
ProcessStartInfo ps = new ProcessStartInfo();
ps.FileName = FindMediaPlayerPath("mplayer.exe");
ps.UseShellExecute = false;
ps.RedirectStandardInput = true;
ps.RedirectStandardError = true;
ps.RedirectStandardOutput = true;
ps.CreateNoWindow = true;
ps.WorkingDirectory = #"x:\";
args = "-wid ";
args += Variables.MediaPlayerHandle;
args += " -ao pcm:fast:file=";
args += DestinationFileName;
if (NeedToCut == true)
{
args += " -ss " + Start + " -endpos " + End;
}
//args += " -vo null -vc null -quiet ";
//-wid will tell MPlayer to show output inisde our panel
args += " " + SourceFileName;
ps.Arguments = args;
using (DumpWav_Process = Process.Start(ps))
using (ManualResetEvent mreOut = new ManualResetEvent(false),
mreErr = new ManualResetEvent(false))
{
DumpWav_Process.OutputDataReceived += (o, e) => { if (e.Data == null) mreOut.Set(); else output(e.Data); };
DumpWav_Process.BeginOutputReadLine();
DumpWav_Process.ErrorDataReceived += (o, e) => { if (e.Data == null) mreErr.Set(); else output(e.Data); }; ;
DumpWav_Process.BeginErrorReadLine();
output = s => DumpWav_ElaborateOutput(s);
DumpWav_ProcessID = DumpWav_Process.Id;
//processMP.StandardInput.Close();
DumpWav_Process.WaitForExit();
mreOut.WaitOne();
mreErr.WaitOne();
//stringa di ritorno (tutto il contenuto della console)
return DumpWav_ConsoleOutput;
}
}
//controlliamo l'output della console
private void DumpWav_ElaborateOutput(string output)
{
Variables.ConsoleOutputMP = Variables.ConsoleOutputMP + output + Environment.NewLine;
if (output.IndexOf("A:") != -1)
{
//some check here
}
}
I recently added this:
ps.WorkingDirectory = #"x:\";
But the result not change, the video speed is not fast and the wav file is not created by Mplayer.
In my app, like the C test, i receive some errors:
[AO PCM] Failed to open aaa.wav for writing!
Failed to initialize audio driver 'pcm:fast:file=aaa.wav'
One more question, when i use mPlayer to encapsulate videos inside my app the process start about one minute after i launched it... maybe concatenate with dumping issue?
Please, any suggestion?
Edit:
I discovered just now: If i start the command prompt with admin rights then also in C Drive Mplayer do the job in the right way...
My app unfortunately don't. I edited the manifest to grant admin rights but it's the same. Somewhere here at stackoverflow i read something about to useshellexecute to true but unfortunately by this way (i need to test anyway) i lose the ability to redirect input/output/error.
I need to find a way to start the process (then the mplayer.exe) from within my app, with admin rights, without use shellexecute...
Edit 2°
I created a simple button with this code:
string args;
//Handle della finestra di Media Player
Variables.MediaPlayerHandle = 0;
Variables.MediaPlayerHandle = (int)MediaPlayer.Handle;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = FindMediaPlayerPath("mplayer.exe");
//psi.FileName = #"x:\mplayer.exe";
psi.UseShellExecute = true;
psi.CreateNoWindow = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.WorkingDirectory = Environment.CurrentDirectory; ;
psi.Verb = "runas";
args = "-wid ";
args += Variables.MediaPlayerHandle;
args += " -ao pcm:fast:file=";
args += #"x:\aaa.wav";
args += #" x:\aaa.avi";
psi.Arguments = args;
Process.Start(psi);
:-( same result, Mplayer is not able to open audio driver and to save file..
Fail, again.. 3° edit:
I tried using CMD:
private void button2_Click(object sender, EventArgs e)
{
ProcessStartInfo processInfo;
Process process;
Variables.MediaPlayerHandle = 0;
Variables.MediaPlayerHandle = (int)MediaPlayer.Handle;
string args = "";
args = #"x:\mplayer.exe -wid " + Variables.MediaPlayerHandle + #" -ao pcm:fast:file=x:\aaa.wav x:\aaa.avi";
MessageBox.Show(args);
processInfo = new ProcessStartInfo("cmd.exe", "/c " + args);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = true;
processInfo.Verb = "runas";
process = Process.Start(processInfo);
process.WaitForExit();
MessageBox.Show("terminato");
process.Close();
}
Now i see the first frame of the video and Mplayer freeze...
I'm losing my hope to use mplayer :-(
Finally i solved...
This is the code:
if (output == null)
throw new ArgumentNullException("output");
string args;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = FindMediaPlayerPath("mplayer.exe");
//psi.FileName = #"x:\mplayer.exe";
psi.UseShellExecute = false;
psi.RedirectStandardInput = true;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.CreateNoWindow = true;
psi.WorkingDirectory = Path.GetDirectoryName(DestinationFileName);
psi.Verb = "runas";
args = "-wid ";
args += Variables.MediaPlayerHandle;
args += " -ao pcm:fast:file=";
args += Path.GetFileName(DestinationFileName);
if (NeedToCut == true)
{
args += " -ss " + Start + " -endpos " + End;
}
//args += " -vo null -vc null -quiet ";
//-wid will tell MPlayer to show output inisde our panel
args += " " + SourceFileName;
psi.Arguments = args;
As i understand i need to move the Process.WorkingDirectory to the same folder as the destination file (in my case the wav).
Now it rocks :-)
NO need for UAC
NO need for useshellexecute = true
Thanks stanley for your help!
I use this method to compile C++ file in VS. But even i provide the correct file it returns false. Can any one help me...
This is class called CL
class CL
{
private const string clexe = #"cl.exe";
private const string exe = "Test.exe", file = "test.cpp";
private string args;
public CL(String[] args)
{
this.args = String.Join(" ", args);
this.args += (args.Length > 0 ? " " : "") + "/Fe" + exe + " " + file;
}
public Boolean Compile(String content, ref string errors)
{
if (File.Exists(exe))
File.Delete(exe);
if (File.Exists(file))
File.Delete(file);
File.WriteAllText(file, content);
Process proc = new Process();
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.FileName = clexe;
proc.StartInfo.Arguments = this.args;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
//errors += proc.StandardError.ReadToEnd();
errors += proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
bool success = File.Exists(exe);
return success;
}
}
This is my button click event
private void button1_Click(object sender, EventArgs e)
{
string content = "#include <stdio.h>\nmain(){\nprintf(\"Hello world\");\n}\n";
string errors = "";
CL k = new CL(new string[] { });
if (k.Compile(content, ref errors))
Console.WriteLine("Success!");
else
MessageBox.Show("Errors are : ", errors);
}
In your Visual Studio installation folder there should be the following path:
VC\bin\x86_amd64\1033\1033
There should be a clui.dll in this path. Copy it to the parent folder (VC\bin\x86_amd64\1033). This should solve your problem.
I took the solution from http://connect.microsoft.com/VisualStudio/feedback/details/108528/command-line-issue-when-building-for-64bit-in-32bit-with-cl-exe:
Maybe it is not relevant, but I think you miss a space in your command line...
this.args += (args.Length > 0 ? " " : "") + "/Fe" + exe + " " + file;
right after the "/Fe"
How do I execute a command-line program from C# and get back the STD OUT results? Specifically, I want to execute DIFF on two files that are programmatically selected and write the results to a text box.
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "YOURBATCHFILE.bat";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Code is from MSDN.
Here's a quick sample:
//Create process
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
//strCommand is path and file name of command to run
pProcess.StartInfo.FileName = strCommand;
//strCommandParameters are parameters to pass to program
pProcess.StartInfo.Arguments = strCommandParameters;
pProcess.StartInfo.UseShellExecute = false;
//Set output of program to be written to process output stream
pProcess.StartInfo.RedirectStandardOutput = true;
//Optional
pProcess.StartInfo.WorkingDirectory = strWorkingDirectory;
//Start the process
pProcess.Start();
//Get program output
string strOutput = pProcess.StandardOutput.ReadToEnd();
//Wait for process to finish
pProcess.WaitForExit();
There one other parameter I found useful, which I use to eliminate the process window
pProcess.StartInfo.CreateNoWindow = true;
this helps to hide the black console window from user completely, if that is what you desire.
// usage
const string ToolFileName = "example.exe";
string output = RunExternalExe(ToolFileName);
public string RunExternalExe(string filename, string arguments = null)
{
var process = new Process();
process.StartInfo.FileName = filename;
if (!string.IsNullOrEmpty(arguments))
{
process.StartInfo.Arguments = arguments;
}
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
var stdOutput = new StringBuilder();
process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data); // Use AppendLine rather than Append since args.Data is one line of output, not including the newline character.
string stdError = null;
try
{
process.Start();
process.BeginOutputReadLine();
stdError = process.StandardError.ReadToEnd();
process.WaitForExit();
}
catch (Exception e)
{
throw new Exception("OS error while executing " + Format(filename, arguments)+ ": " + e.Message, e);
}
if (process.ExitCode == 0)
{
return stdOutput.ToString();
}
else
{
var message = new StringBuilder();
if (!string.IsNullOrEmpty(stdError))
{
message.AppendLine(stdError);
}
if (stdOutput.Length != 0)
{
message.AppendLine("Std output:");
message.AppendLine(stdOutput.ToString());
}
throw new Exception(Format(filename, arguments) + " finished with exit code = " + process.ExitCode + ": " + message);
}
}
private string Format(string filename, string arguments)
{
return "'" + filename +
((string.IsNullOrEmpty(arguments)) ? string.Empty : " " + arguments) +
"'";
}
The accepted answer on this page has a weakness that is troublesome in rare situations. There are two file handles which programs write to by convention, stdout, and stderr.
If you just read a single file handle such as the answer from Ray, and the program you are starting writes enough output to stderr, it will fill up the output stderr buffer and block. Then your two processes are deadlocked. The buffer size may be 4K.
This is extremely rare on short-lived programs, but if you have a long running program which repeatedly outputs to stderr, it will happen eventually. This is tricky to debug and track down.
There are a couple good ways to deal with this.
One way is to execute cmd.exe instead of your program and use the /c argument to cmd.exe to invoke your program along with the "2>&1" argument to cmd.exe to tell it to merge stdout and stderr.
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
Another way is to use a programming model which reads both handles at the same time.
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = #"/c dir \windows";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = false;
p.OutputDataReceived += (a, b) => Console.WriteLine(b.Data);
p.ErrorDataReceived += (a, b) => Console.WriteLine(b.Data);
p.Start();
p.BeginErrorReadLine();
p.BeginOutputReadLine();
p.WaitForExit();
System.Diagnostics.ProcessStartInfo psi =
new System.Diagnostics.ProcessStartInfo(#"program_to_call.exe");
psi.RedirectStandardOutput = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
System.Diagnostics.Process proc = System.Diagnostics.Process.Start(psi); ////
System.IO.StreamReader myOutput = proc.StandardOutput;
proc.WaitForExit(2000);
if (proc.HasExited)
{
string output = myOutput.ReadToEnd();
}
You will need to use ProcessStartInfo with RedirectStandardOutput enabled - then you can read the output stream. You might find it easier to use ">" to redirect the output to a file (via the OS), and then simply read the file.
[edit: like what Ray did: +1]
One-liner run command:
new Process() { StartInfo = new ProcessStartInfo("echo", "Hello, World") }.Start();
Read output of command in shortest amount of reable code:
var cliProcess = new Process() {
StartInfo = new ProcessStartInfo("echo", "Hello, World") {
UseShellExecute = false,
RedirectStandardOutput = true
}
};
cliProcess.Start();
string cliOut = cliProcess.StandardOutput.ReadToEnd();
cliProcess.WaitForExit();
cliProcess.Close();
In case you also need to execute some command in the cmd.exe, you can do the following:
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/C vol";
p.Start();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);
This returns just the output of the command itself:
You can also use StandardInput instead of StartInfo.Arguments:
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.Start();
// Read the output stream first and then wait.
p.StandardInput.WriteLine("vol");
p.StandardInput.WriteLine("exit");
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);
The result looks like this:
Since the most answers here dont implement the using statemant for IDisposable and some other stuff wich I think could be nessecary I will add this answer.
For C# 8.0
// Start a process with the filename or path with filename e.g. "cmd". Please note the
//using statemant
using myProcess.StartInfo.FileName = "cmd";
// add the arguments - Note add "/c" if you want to carry out tge argument in cmd and
// terminate
myProcess.StartInfo.Arguments = "/c dir";
// Allows to raise events
myProcess.EnableRaisingEvents = true;
//hosted by the application itself to not open a black cmd window
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.CreateNoWindow = true;
// Eventhander for data
myProcess.Exited += OnOutputDataRecived;
// Eventhandler for error
myProcess.ErrorDataReceived += OnErrorDataReceived;
// Eventhandler wich fires when exited
myProcess.Exited += OnExited;
// Starts the process
myProcess.Start();
//read the output before you wait for exit
myProcess.BeginOutputReadLine();
// wait for the finish - this will block (leave this out if you dont want to wait for
// it, so it runs without blocking)
process.WaitForExit();
// Handle the dataevent
private void OnOutputDataRecived(object sender, DataReceivedEventArgs e)
{
//do something with your data
Trace.WriteLine(e.Data);
}
//Handle the error
private void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Trace.WriteLine(e.Data);
//do something with your exception
throw new Exception();
}
// Handle Exited event and display process information.
private void OnExited(object sender, System.EventArgs e)
{
Trace.WriteLine("Process exited");
}
Here is small example:
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
var p = Process.Start(
new ProcessStartInfo("git", "branch --show-current")
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
WorkingDirectory = Environment.CurrentDirectory
}
);
p.WaitForExit();
string branchName =p.StandardOutput.ReadToEnd().TrimEnd();
string errorInfoIfAny =p.StandardError.ReadToEnd().TrimEnd();
if (errorInfoIfAny.Length != 0)
{
Console.WriteLine($"error: {errorInfoIfAny}");
}
else {
Console.WriteLine($"branch: {branchName}");
}
}
}
I believe this is shortest form.
Please notice that most of command line tools easily confuse standard output and standard error, sometimes it makes sense just to clue those together into single string.
Also p.ExitCode might be sometimes useful.
Example above serves for purpose of writing command line utility like tools if you want to do it by yourself. Please note that for cli automation it's also possible to use Cake Frosten and Cake Git extension.
You can launch any command line program using the Process class, and set the StandardOutput property of the Process instance with a stream reader you create (either based on a string or a memory location). After the process completes, you can then do whatever diff you need to on that stream.
This might be useful for someone if your attempting to query the local ARP cache on a PC/Server.
List<string[]> results = new List<string[]>();
using (Process p = new Process())
{
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.Arguments = "/c arp -a";
p.StartInfo.FileName = #"C:\Windows\System32\cmd.exe";
p.Start();
string line;
while ((line = p.StandardOutput.ReadLine()) != null)
{
if (line != "" && !line.Contains("Interface") && !line.Contains("Physical Address"))
{
var lineArr = line.Trim().Split(' ').Select(n => n).Where(n => !string.IsNullOrEmpty(n)).ToArray();
var arrResult = new string[]
{
lineArr[0],
lineArr[1],
lineArr[2]
};
results.Add(arrResult);
}
}
p.WaitForExit();
}
This may not be the best/easiest way, but may be an option:
When you execute from your code, add " > output.txt" and then read in the output.txt file.
There is a ProcessHelper Class in PublicDomain open source code which might interest you.
Julian's solution is tested working with some minor corrections. The following is an example that also used https://sourceforge.net/projects/bat-to-exe/ GenericConsole.cs and https://www.codeproject.com/Articles/19225/Bat-file-compiler program.txt for args part:
using System;
using System.Text; //StringBuilder
using System.Diagnostics;
using System.IO;
class Program
{
private static bool redirectStandardOutput = true;
private static string buildargument(string[] args)
{
StringBuilder arg = new StringBuilder();
for (int i = 0; i < args.Length; i++)
{
arg.Append("\"" + args[i] + "\" ");
}
return arg.ToString();
}
static void Main(string[] args)
{
Process prc = new Process();
prc.StartInfo = //new ProcessStartInfo("cmd.exe", String.Format("/c \"\"{0}\" {1}", Path.Combine(Environment.CurrentDirectory, "mapTargetIDToTargetNameA3.bat"), buildargument(args)));
//new ProcessStartInfo(Path.Combine(Environment.CurrentDirectory, "mapTargetIDToTargetNameA3.bat"), buildargument(args));
new ProcessStartInfo("mapTargetIDToTargetNameA3.bat");
prc.StartInfo.Arguments = buildargument(args);
prc.EnableRaisingEvents = true;
if (redirectStandardOutput == true)
{
prc.StartInfo.UseShellExecute = false;
}
else
{
prc.StartInfo.UseShellExecute = true;
}
prc.StartInfo.CreateNoWindow = true;
prc.OutputDataReceived += OnOutputDataRecived;
prc.ErrorDataReceived += OnErrorDataReceived;
//prc.Exited += OnExited;
prc.StartInfo.RedirectStandardOutput = redirectStandardOutput;
prc.StartInfo.RedirectStandardError = redirectStandardOutput;
try
{
prc.Start();
prc.BeginOutputReadLine();
prc.BeginErrorReadLine();
prc.WaitForExit();
}
catch (Exception e)
{
Console.WriteLine("OS error: " + e.Message);
}
prc.Close();
}
// Handle the dataevent
private static void OnOutputDataRecived(object sender, DataReceivedEventArgs e)
{
//do something with your data
Console.WriteLine(e.Data);
}
//Handle the error
private static void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
// Handle Exited event and display process information.
//private static void OnExited(object sender, System.EventArgs e)
//{
// var process = sender as Process;
// if (process != null)
// {
// Console.WriteLine("ExitCode: " + process.ExitCode);
// }
// else
// {
// Console.WriteLine("Process exited");
// }
//}
}
The code need to compile inside VS2007, using commandline csc.exe generated executable will not show console output correctly, or even crash with CLR20r3 error. Comment out the OnExited event process, the console output of the bat to exe will be more like the original bat console output.
Just for fun, here's my completed solution for getting PYTHON output - under a button click - with error reporting. Just add a button called "butPython" and a label called "llHello"...
private void butPython(object sender, EventArgs e)
{
llHello.Text = "Calling Python...";
this.Refresh();
Tuple<String,String> python = GoPython(#"C:\Users\BLAH\Desktop\Code\Python\BLAH.py");
llHello.Text = python.Item1; // Show result.
if (python.Item2.Length > 0) MessageBox.Show("Sorry, there was an error:" + Environment.NewLine + python.Item2);
}
public Tuple<String,String> GoPython(string pythonFile, string moreArgs = "")
{
ProcessStartInfo PSI = new ProcessStartInfo();
PSI.FileName = "py.exe";
PSI.Arguments = string.Format("\"{0}\" {1}", pythonFile, moreArgs);
PSI.CreateNoWindow = true;
PSI.UseShellExecute = false;
PSI.RedirectStandardError = true;
PSI.RedirectStandardOutput = true;
using (Process process = Process.Start(PSI))
using (StreamReader reader = process.StandardOutput)
{
string stderr = process.StandardError.ReadToEnd(); // Error(s)!!
string result = reader.ReadToEnd(); // What we want.
return new Tuple<String,String> (result,stderr);
}
}