Hi according to my last question here I try to write a sql editor or some thing like this,in this way I try to connect to CMD from C# and execute my command.
Now my problem is I connect to SQLPLUS after that I cant get SQLPLUS command,and the other resource I review don't satisfy me. Please help me how after I connected to sqlplus , I can a live my process to run my sql command? right now I use this code:
//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();
I customized it. I separate the initialize, I created the process object one time I still have problem, to run the second command I use these codes for the second call:
pProcess.StartInfo.FileName = strCommand;
//strCommandParameters are parameters to pass to program
pProcess.StartInfo.Arguments = strCommandParameters;
//Start the process
pProcess.Start();
//Get program output
string strOutput = pProcess.StandardOutput.ReadToEnd();
//Wait for process to finish
pProcess.WaitForExit();
Thanks in advance
Your question is a little confusing but I think i see your problem. First you should check out this blog post to see common issues with System.Diagnostics.Process. Your code happens to violate one that isn't listed there. The reuse of the Process object itself.
You need to refactor the code like:
class MyProcessStarter
{
private ProcessStartInfo _startInfo = new ProcessStartInfo();
public MyProcessStarter(string exe, string workingDir)
{
_startInfo.WorkingDirectory = workingDir;
_startInfo.FileName = exe;
_startInfo.UseShellExecute = false;
_startInfo.RedirectStandardOutput = true;
}
public string Run(string arguments)
{
_startInfo.Arguments = arguments;
Process p = Process.Start(_startInfo);
p.Start();
string strOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
return strOutput;
}
}
I've written a more complete and accurate implementation called ProcessRunner. The following demonstrates it's usage to perform the same operation:
using CSharpTest.Net.Processes;
partial class Program
{
static int Main(string[] args)
{
ProcessRunner run = new ProcessRunner("svn.exe");
run.OutputReceived += new ProcessOutputEventHandler(run_OutputReceived);
return run.Run("update", "C:\\MyProject");
}
static void run_OutputReceived(object sender, ProcessOutputEventArgs args)
{
Console.WriteLine("{0}: {1}", args.Error ? "Error" : "Output", args.Data);
}
}
You need to READ ALL data from input, before send another command!
And you can't ask to READ if no data is avaliable... little bit suck isn't?
My solutions... when ask to read... ask to read a big buffer... like 1 MEGA...
And you will need wait a min 100 milliseconds... sample code...
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim oProcess As New Process()
Dim oStartInfo As New ProcessStartInfo("cmd.exe", "")
oStartInfo.UseShellExecute = False
oStartInfo.RedirectStandardOutput = True
oStartInfo.RedirectStandardInput = True
oStartInfo.CreateNoWindow = True
oProcess.StartInfo = oStartInfo
oProcess.Start()
oProcess.StandardInput.WriteLine("dir")
Threading.Thread.Sleep(100)
Dim Response As String = String.Empty
Dim BuffSize As Integer = 1024 * 1024
Dim bytesRead As Integer = 0
Do
Dim x As Char() = New Char(BuffSize - 1) {}
bytesRead = oProcess.StandardOutput.Read(x, 0, BuffSize)
Response = String.Concat(Response, String.Join("", x).Substring(0, bytesRead))
Loop While oProcess.StandardOutput.Peek >= 0
MsgBox(Response)
Response = String.Empty
oProcess.StandardInput.WriteLine("dir c:\")
Threading.Thread.Sleep(100)
bytesRead = 0
Do
Dim x As Char() = New Char(BuffSize - 1) {}
bytesRead = oProcess.StandardOutput.Read(x, 0, BuffSize)
Response = String.Concat(Response, String.Join("", x).Substring(0, bytesRead))
'Response = String.Concat(Response, String.Join("", x))
Loop While oProcess.StandardOutput.Peek >= 0
MsgBox(Response)
End Sub
End Class
Related
I have c# program that I want to run but from the cmd using a command line so here is my question I don't know how to create the command and I don't know how to send the parameter in my command to some function there.
You can use the Process class to execute files
var fileName = "some.exe";
var arguments = "";
var info = new System.Diagnostics.ProcessStartInfo(fileName, arguments);
info.UseShellExecute = false;
info.CreateNoWindow = true;
// if you want read output
info.RedirectStandardOutput = true;
var process = new System.Diagnostics.Process { StartInfo = info };
process.Start();
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError?.ReadToEnd();
You can create a console application and after generating (by building) .exe file, you can call with the arguments in command line.
Sample Example:
class Program
{
static void Main(string[] args)
{
var a = Convert.ToInt32(args[0]);
var b = Convert.ToInt32(args[1]);
Console.WriteLine(a+b);
}
}
OUTPUT
I'm trying to write a program which executes 2 different .exe files and outputs their results to a text file. When I execute them separately, they work fine, but when I try to execute them both, the second process doesn't run. Can anyone help?
Here is the code. Player1.exe and Player2.exe are console applications returning 0 or 1.
static void Main(string[] args)
{
Process process1 = new Process();
process1.StartInfo.FileName = "C:/Programming/Tournament/Player1.exe";
process1.StartInfo.Arguments = "";
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.RedirectStandardOutput = true;
process1.Start();
var result1 = process1.StandardOutput.ReadToEnd();
process1.Close();
Process process2 = new Process();
process2.StartInfo.FileName = "C:/Programming/Tournament/Player2.exe";
process2.StartInfo.Arguments = "";
process2.StartInfo.UseShellExecute = false;
process2.StartInfo.RedirectStandardOutput = true;
process2.Start();
string result2 = process2.StandardOutput.ReadToEnd().ToString();
process2.Close();
string resultsPath = "C:/Programming/Tournament/Results/Player1vsPlayer2.txt";
if (!File.Exists(resultsPath))
{
StreamWriter sw = File.CreateText(resultsPath);
sw.WriteLine("Player1 " + "Player2");
sw.WriteLine(result1 + " " + result2);
sw.Flush();
}
}
1.
you wrote in a comment: "The program doesn't even reach to process2. I tested that by putting a breakpoint."
process1.Start() may be throwing an exception. Rather than setting a breakpoint at process2, step through the lines and find the exception. Or better yet, add a try/catch block and report an error.
2.
Another possibility is that ReadToEnd is not behaving as expected. You can Peek and see if there is more data to read by looping like this:
var result1 = new StringBuilder()
while (process1.StandardOutput.Peek() > -1)
{
result1.Append(process1.StandardOutput.ReadLine());
}
3.
If these processes don't immediately provide data and end, then you need to get them both started before you begin waiting on their StandardOutput. Call Start() on each process before doing the reads.
I don't know too much about using process, but I use this approach when I need separate things to run at once. I didn't pull in the bottom portion of your project, but check this out to see if it helps in any way.
class Program
{
static void Main(string[] args)
{
Process process1 = new Process();
process1.StartInfo.FileName = "C:/Programming/Tournament/Player1.exe";
process1.StartInfo.Arguments = "";
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.RedirectStandardOutput = true;
Process process2 = new Process();
process2.StartInfo.FileName = "C:/Programming/Tournament/Player2.exe";
process2.StartInfo.Arguments = "";
process2.StartInfo.UseShellExecute = false;
process2.StartInfo.RedirectStandardOutput = true;
Thread T1 = new Thread(delegate() {
doProcess(process1);
});
Thread T2 = new Thread(delegate() {
doProcess(process2);
});
T1.Start();
T2.Start();
}
public static void doProcess(Process myProcess)
{
myProcess.Start();
var result1 = myProcess.StandardOutput.ReadToEnd();
myProcess.Close();
}
}
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.
I want to using C# process to get result from Command Prompt. The command is "java HelloWorld 1" (I have been build it to HelloWorld.class file using "javac HelloWorld.java")
The java code:
public class HelloWorld {
public HelloWorld() {}
public static void main(String[] args) { System.out.println("STARTED");
try {
int param = Integer.parseInt(args[0].toString());
if (param == 1) {
System.out.println("BASE 64!");
} else if (param == 2) {
System.out.println("MD5!");
} else {
System.out.println("INPUT NOT MATCH!");
}
} catch (Exception ee) {
System.out.println("NO INPUT - ERROR");
}
} }
and The C# code:
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "C:\\Program Files\\Java\\jdk1.6.0_25\\bin\\java.exe";
p.StartInfo.Arguments = "HelloWorld 1";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string strOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
But the strOutput is "".
Can you give me the solution?
Thank you!
The most likely thing is that java cannot find your HelloWorld.class file.
In that case, it will write to the standard error something like
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld
Caused by: java.lang.ClassNotFoundException: HelloWorld
and then a stack trace.
And it will not write anything to the standard output
I suggest you do two things:
1) read from standard error as well and see what that says
2) add a classpath argument prior to the class file
p.StartInfo.Arguments = " -cp C:\\code\\myapp HelloWorld 1";
(Obviously substituting in the correct path to the folder that contains HelloWorld.class)
Another alternative is to set your process start info to the location of HelloWorld:
ProcessStartInfo pInfo = new ProcessStartInfo(#"C:\Program Files\Java\jdk1.6.0_25\bin\java.exe");
pInfo.Arguments = = "HelloWorld";
pInfo.WorkingDirectory = #"C:\JavaFiles";
pInfo.UseShellExecute = false;
pInfo.RedirectStandardOutput = true;
Process javaProc = Process.Start(pInfo);
string output = javaProc.StandarOutput.ReadToEnd();
EDIT: I just realized your p was a Process object. WorkingDirectory is a property of ProcessStartInfo
This is assuming that C:\JavaFiles\HelloWorld.class and C:\JavaFiles\HelloWorld.java exists. You should also follow Greg's advice and read StandardError, as it will help you troubleshoot future problems
I have a GUI application within which i'm spawning a console application using Process class.
Process p1 = new Process();
p1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p1.StartInfo.CreateNoWindow = true;
p1.StartInfo.UseShellExecute = false;
p1.StartInfo.FileName = Path.Combine(basepath, "abc.exe");
p1.StartInfo.Arguments = "/pn abc.exe /f \"temp1.txt\"";
p1.StartInfo.RedirectStandardError = true;
p1.StartInfo.RedirectStandardInput = true;
p1.StartInfo.RedirectStandardOutput = true;
p1.OutputDataReceived += new DataReceivedEventHandler(outputreceived);
p1.ErrorDataReceived += new DataReceivedEventHandler(errorreceived);
p1.Start();
tocmd = p1.StandardInput;
p1.BeginOutputReadLine();
p1.BeginErrorReadLine();
Now i have a problem that, though it reads the console output asynchronously but it seems to fire the event only when the internal buffer is filled with some amount. I want it to display data as it comes. If there's 10 bytes in buffer, let it display the 10 bytes. My program implements sleep() call internally, so i need to print the data till it goes to sleep.
How can i do it?
=============
As it was mentioned the output is line buffered, i tried the following change in the code
p1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p1.StartInfo.CreateNoWindow = true;
p1.StartInfo.UseShellExecute = false;
p1.StartInfo.FileName = Path.Combine(basepath, "abc.exe");
p1.StartInfo.Arguments = pnswitch + " /f \"temp1.txt\"";
p1.StartInfo.RedirectStandardError = false;
p1.StartInfo.RedirectStandardInput = true;
p1.StartInfo.RedirectStandardOutput = true;
p1.Start();
tocmd = p1.StandardInput;
MethodInvoker mi = new MethodInvoker(readout);
mi.BeginInvoke(null, p1);
and inside readout i wrote
void readout()
{
string str;
while ((str = p1.StandardOutput.ReadLine()) != null)
{
richTextBox1.Invoke(new UpdateOutputCallback(this.updateoutput), new object[] { str });
p1.StandardOutput.BaseStream.Flush();
}
}
So i think it now monitors when each line is written and it prints it right? this too didn't work. Any thing wrong there?
The Output and Error Data received is line buffered, and will only fire when a newline is added.
Your best bet is to use you own reader that can read the input, byte by byte. Obvioulsly, this would have to be non-blocking :)
In order to achieve this, you must use synchronous read operations on a redirected stream.
Your code would look like this (MSDN Sample):
// 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 = "Write500Lines.exe";
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();
In order to achieve async behavior you would have to use some threads.
MSDN Article here