C# Error in Executing multiple command lines - c#

I used this code to execute multi cmd commands in C#.
First i created constructor to create process.
public CMD()
{
process = new Process();
startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.FileName = "cmd.exe";
startInfo.Verb = "runas";
process.StartInfo = startInfo;
process.Start();
process.EnableRaisingEvents = true;
process.StandardInput.AutoFlush = true;
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.OutputDataReceived += Process_OutputDataReceived;
process.ErrorDataReceived += Process_ErrorDataReceived;
process.Exited += Process_Exited;
}
then i used this code to execute multi commands.
public void _cmd(string command)
{
using (StreamWriter sw = process.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine(command);
}
}
}
for the first command is not any problem but when i send second one i got this error in sw.BaseStream.CanWrite line.
Object reference not set to an instance of an object.
when i debug code for the first time sw.BaseStream is OK but in second command it get null
what is problem here ?

I suspect it's because of your using statement. When the using block is exited, it will call Dispose in process.StandardInput().

Related

Command hanging in C# when running Postman's Newman command

I'm trying to use cmd CLI to excute a newman collection run. However when the process is running it's getting stuck and never finishes processing.
Any suggestions on how to deal with that?
string cmdCommand="newman run demo.postman_collection.json --env-var HTTP_PROXY --insecure";
int TotalTimeout= 150000;
CliProcess = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new
System.Diagnostics.ProcessStartInfo();
if (_inputDir != null)
{
startInfo.WorkingDirectory = _inputDir;
}
//startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = false;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C "+cmdCommand;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardInput = true;
bool processExited;
startInfo.RedirectStandardOutput = false;
CliProcess.StartInfo = startInfo;
CliProcess.Start();
CliProcess.StandardInput.WriteLine("exit");
//CliProcess.BeginOutputReadLine();
//CliProcess.BeginErrorReadLine();
//CliProcess.Close();
processExited = CliProcess.WaitForExit(TotalTimeout);
// //&& outputWaitHandle.WaitOne(TotalTimeout) && errorWaitHandle.WaitOne(TotalTimeout);
//CliProcess.CancelOutputRead();
//CliProcess.CancelErrorRead();
//ExitCode = GetProcessExitCode();
//CliProcess.Kill();
//}
//Wait additional minute for the process to exit
if (!processExited)
{
KillNewman();
TraceLogger.Instance.LogMessage(TraceLevel.Warning, MsgSrc, "[SendCmdCommand(string cmdCommand)] Newman process was killed due to timeout");
}
This is the most I can get out of it:
It gets stuck here^ and never continues.
the problem was due to the fact that the proxy was misconfigured so the request was sent trying to get to an unresponsive proxy server...
So in conclusion, there was nothing wrong with the code itself.

C# Running exe through process, how to hide window

Im running an exe through process in my c# program, i want the process to be completely invisible without the console of it popping up.
This is my code
Process process2 = new Process();
process2.StartInfo.FileName = "cmd.exe";
process2.StartInfo.UseShellExecute = false;
process2.StartInfo.CreateNoWindow = true;
process2.StartInfo.RedirectStandardOutput = true;
process2.StartInfo.RedirectStandardError = true;
process2.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process2 = Process.Start(path3);
even with this code the console window still opens and shows, any help will be appreciated :)
Using
UseShellExecute = false; CreateNoWindow = true;
Should hide the process although it depends on the path in which you are opening, if the process has a force show
Try the following:
private void RunCmd(string exePath, string arguments = null)
{
//create new instance
ProcessStartInfo startInfo = new ProcessStartInfo(exePath, arguments);
startInfo.Arguments = arguments; //arguments
startInfo.CreateNoWindow = true; //don't create a window
startInfo.RedirectStandardError = true; //redirect standard error
startInfo.RedirectStandardOutput = true; //redirect standard output
startInfo.RedirectStandardInput = false;
startInfo.UseShellExecute = false; //if true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.ErrorDialog = false;
//create new instance
using (Process p = new Process { StartInfo = startInfo, EnableRaisingEvents = true })
{
//subscribe to event and add event handler code
p.ErrorDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Error: " + e.Data);
}
};
//subscribe to event and add event handler code
p.OutputDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Output: " + e.Data);
}
};
p.Start(); //start
p.BeginErrorReadLine(); //begin async reading for standard error
p.BeginOutputReadLine(); //begin async reading for standard output
//waits until the process is finished before continuing
p.WaitForExit();
}
}
See also this post.
I fixed it by renaming the window instead ty for all your help

Problem with running batch files from within my application

I've been trying to create a simple application to backup my Windows Server databases aswell as a whole server backup.
For this I want to use batch files which are being executed by my application.
I tried several approaches but for some reason it always fails so I'd be happy if you could help me out.
Batch file BACKUPSERVER:
wbadmin start backup -backupTarget:D: -include:C: -allCritical -quiet
I have to run the bat as administrator or it fails due to missing permissions.
C# code:
static Task<int> RunProcessAsync(string fileName)
{
............
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.Verb = "runas";
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/C \"D:\\SQLBACKUP\\BACKUPSERVER.bat\"";
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
Debugging says 'wbadmin wasnt found'. 'runas' activated or not doesn't make any difference.
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = fileName;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = true;
startInfo.CreateNoWindow = false;
// startInfo.Verb = "runas";
var process = new Process
{
StartInfo = { FileName = fileName },
EnableRaisingEvents = true
};
process.StartInfo = startInfo;
process.Exited += (sender, args) =>
{
tcs.SetResult(process.ExitCode);
process.Dispose();
};
process.Start();
Also doesn't work.
Any ideas?
EDIT:
I'm able to run commands like shutdown but wbadmin doesn't work whatsoever...
This is how I solved the problem:
Make sure ure compiling for 64bit if u intend to use your application on 64bit system, otherwise it will redirect to different subfolders and wont find 'wbadmin.exe'.
Run wbadmin with ProcessStart or run a batch but without direct cmd input, so use this with filename = batch file or wbadmin with startInfo.Arguments:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = fileName;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = true;
startInfo.CreateNoWindow = false;
// startInfo.Verb = "runas";
var process = new Process
{
StartInfo = { FileName = fileName },
EnableRaisingEvents = true
};
process.StartInfo = startInfo;
process.Exited += (sender, args) =>
{
tcs.SetResult(process.ExitCode);
process.Dispose();
};
process.Start();
Make sure u request administrator rights

Run command line command passing STDIN [duplicate]

This question already has answers here:
Capturing console output from a .NET application (C#)
(8 answers)
Closed 6 years ago.
I need to spawn a child process that is a console application, and capture its output.
I wrote up the following code for a method:
string retMessage = String.Empty;
ProcessStartInfo startInfo = new ProcessStartInfo();
Process p = new Process();
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;
startInfo.Arguments = command;
startInfo.FileName = exec;
p.StartInfo = startInfo;
p.Start();
p.OutputDataReceived += new DataReceivedEventHandler
(
delegate(object sender, DataReceivedEventArgs e)
{
using (StreamReader output = p.StandardOutput)
{
retMessage = output.ReadToEnd();
}
}
);
p.WaitForExit();
return retMessage;
However, this does not return anything. I don't believe the OutputDataReceived event is being called back, or the WaitForExit() command may be blocking the thread so it will never callback.
Any advice?
EDIT: Looks like I was trying too hard with the callback. Doing:
return p.StandardOutput.ReadToEnd();
Appears to work fine.
Here's code that I've verified to work. I use it for spawning MSBuild and listening to its output:
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += (sender, args) => Console.WriteLine("received output: {0}", args.Data);
process.Start();
process.BeginOutputReadLine();
I just tried this very thing and the following worked for me:
StringBuilder outputBuilder;
ProcessStartInfo processStartInfo;
Process process;
outputBuilder = new StringBuilder();
processStartInfo = new ProcessStartInfo();
processStartInfo.CreateNoWindow = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.UseShellExecute = false;
processStartInfo.Arguments = "<insert command line arguments here>";
processStartInfo.FileName = "<insert tool path here>";
process = new Process();
process.StartInfo = processStartInfo;
// enable raising events because Process does not raise events by default
process.EnableRaisingEvents = true;
// attach the event handler for OutputDataReceived before starting the process
process.OutputDataReceived += new DataReceivedEventHandler
(
delegate(object sender, DataReceivedEventArgs e)
{
// append the new data to the data already read-in
outputBuilder.Append(e.Data);
}
);
// start the process
// then begin asynchronously reading the output
// then wait for the process to exit
// then cancel asynchronously reading the output
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
process.CancelOutputRead();
// use the output
string output = outputBuilder.ToString();
Here's some full and simple code to do this. This worked fine when I used it.
var processStartInfo = new ProcessStartInfo
{
FileName = #"C:\SomeProgram",
Arguments = "Arguments",
RedirectStandardOutput = true,
UseShellExecute = false
};
var process = Process.Start(processStartInfo);
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
Note that this only captures standard output; it doesn't capture standard error. If you want both, use this technique for each stream.
I needed to capture both stdout and stderr and have it timeout if the process didn't exit when expected. I came up with this:
Process process = new Process();
StringBuilder outputStringBuilder = new StringBuilder();
try
{
process.StartInfo.FileName = exeFileName;
process.StartInfo.WorkingDirectory = args.ExeDirectory;
process.StartInfo.Arguments = args;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.EnableRaisingEvents = false;
process.OutputDataReceived += (sender, eventArgs) => outputStringBuilder.AppendLine(eventArgs.Data);
process.ErrorDataReceived += (sender, eventArgs) => outputStringBuilder.AppendLine(eventArgs.Data);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
var processExited = process.WaitForExit(PROCESS_TIMEOUT);
if (processExited == false) // we timed out...
{
process.Kill();
throw new Exception("ERROR: Process took too long to finish");
}
else if (process.ExitCode != 0)
{
var output = outputStringBuilder.ToString();
var prefixMessage = "";
throw new Exception("Process exited with non-zero exit code of: " + process.ExitCode + Environment.NewLine +
"Output from process: " + outputStringBuilder.ToString());
}
}
finally
{
process.Close();
}
I am piping the stdout and stderr into the same string, but you could keep it separate if needed. It uses events, so it should handle them as they come (I believe). I have run this successfully, and will be volume testing it soon.
It looks like two of your lines are out of order. You start the process before setting up an event handler to capture the output. It's possible the process is just finishing before the event handler is added.
Switch the lines like so.
p.OutputDataReceived += ...
p.Start();
Redirecting the stream is asynchronous and will potentially continue after the process has terminated. It is mentioned by Umar to cancel after process termination process.CancelOutputRead(). However that has data loss potential.
This is working reliably for me:
process.WaitForExit(...);
...
while (process.StandardOutput.EndOfStream == false)
{
Thread.Sleep(100);
}
I didn't try this approach but I like the suggestion from Sly:
if (process.WaitForExit(timeout))
{
process.WaitForExit();
}
You need to call p.Start() to actually run the process after you set the StartInfo. As it is, your function is probably hanging on the WaitForExit() call because the process was never actually started.
The answer from Judah did not work for me (or is not complete) as the application was exiting after the first BeginOutputReadLine();
This works for me as a complete snippet, reading the constant output of a ping:
var process = new Process();
process.StartInfo.FileName = "ping";
process.StartInfo.Arguments = "google.com -t";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.OutputDataReceived += (sender, a) => Console.WriteLine(a.Data);
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
Here's a method that I use to run a process and gets its output and errors :
public static string ShellExecute(this string path, string command, TextWriter writer, params string[] arguments)
{
using (var process = Process.Start(new ProcessStartInfo { WorkingDirectory = path, FileName = command, Arguments = string.Join(" ", arguments), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true }))
{
using (process.StandardOutput)
{
writer.WriteLine(process.StandardOutput.ReadToEnd());
}
using (process.StandardError)
{
writer.WriteLine(process.StandardError.ReadToEnd());
}
}
return path;
}
For example :
#"E:\Temp\MyWorkingDirectory".ShellExecute(#"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\svcutil.exe", Console.Out);

Reading output from another running application

I'm working on a custom IDE in C# for a scripting language, and I have a problem.
I'm trying to start the compiler process (pawncc.exe) and pass arguments to it. I've done that, and now I have a problem. When I want to display the output from the compiler application, it only displays some parts of it. It should output this (got this from the command prompt):
Pawn compiler 3.2.3664 Copyright (c) 1997-2006, ITB CompuPhase
newGM.pwn(0) : fatal error 100: cannot read from file: "includes/main_include.inc"
Compilation aborted.
1 Error.
But it doesn't. It outputs this (in the application, using the same command/arguments):
Pawn compiler 3.2.3664 Copyright (c) 1997-2006, ITB CompuPhase
1 Error.
I just don't get it! It's a really weird thing. It might be something simple but I've been looking at it, and researching for hours now! Here's my code:
public Form3(string path)
{
InitializeComponent();
this._path = path;
Process myProcess = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo("pawncc.exe");
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.Arguments = path + " -r -d2";
myProcess.StartInfo = startInfo;
myProcess.Start();
while (true)
{
string myString;
byte[] buffer = new byte[512];
var ar = myProcess.StandardOutput.BaseStream.BeginRead(buffer, 0, 512, null, null);
ar.AsyncWaitHandle.WaitOne();
var bytesRead = myProcess.StandardOutput.BaseStream.EndRead(ar);
if (bytesRead > 0)
{
myString = Encoding.ASCII.GetString(buffer, 0, bytesRead);
}
else
{
myProcess.WaitForExit();
break;
}
richTextBox1.Text = myString;
}
}
!!EDIT:
It does the same thing with this code:
public Form3(string path)
{
InitializeComponent();
this._path = path;
Process myProcess = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo("pawncc.exe");
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.Arguments = path + " -r -d2";
myProcess.StartInfo = startInfo;
myProcess.Start();
using (StreamReader reader = myProcess.StandardOutput)
{
string result = reader.ReadToEnd();
richTextBox1.Text = result;
}
}
You need to redirect the standard error stream as well:
startInfo.RedirectStandardError = true;
Edit: I just reviewed the code and discovered that you are only readonly the StandardOutput stream.
I generally monitor the process for both the standard and error output streams using the DataReceived events on the process and adding the results into a stringbuilder, then storing the StringBuilder content in the UI element:
private static System.Text.StringBuilder m_sbText;
public Form3(string path)
{
InitializeComponent();
this._path = path;
Process myProcess = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo("pawncc.exe");
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.Arguments = path + " -r -d2";
myProcess.StartInfo = startInfo;
m_sbText = new System.Text.StringBuilder(1000);
myProcess.OutputDataReceived += ProcessDataHandler;
myProcess.ErrorDataReceived += ProcessDataHandler;
myProcess.Start();
myProcess.BeginOutputReadLine();
myProcess.BeginErrorReadLine();
while (!myProcess.HasExited)
{
System.Threading.Thread.Sleep(500);
System.Windows.Forms.Application.DoEvents();
}
RichTextBox1.Text = m_sbText.ToString();
}
private static void ProcessDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
// Collect the net view command output.
if (!String.IsNullOrEmpty(outLine.Data))
{
// Add the text to the collected output.
m_sbText.AppendLine(outLine.Data);
}
}
There are obviously variations on this, but this should get you started.
I dont have the pawnCC application so I cant try but it appears they restrict the verbosity of debugging information to external applications - apart from the command prompt.
Can you try spawning the pawncc.exe via cmd:
"cmd.exe \c CommandParameterToLaunchPawnCCwithArguments"
I've noticed some sporadic issues when dealing with the raw output/error streams from spawned processes in the past, hence why I usually deal with captured output via eventing:
Process myProcess = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo("pawncc.exe");
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.Arguments = path + " -r -d2";
myProcess.EnableRaisingEvents = true;
myProcess.OutputDataReceived += OnOutputDataReceived;
myProcess.ErrorDataReceived += OnErrorDataReceived;
myProcess.StartInfo = startInfo;
myProcess.Start();
myProcess.BeginOutputReadLine();
myProcess.BeginErrorReadLine();

Categories

Resources