i have a little question. Is it possible to get the logging stream (logging module) from a python script in C# using Process and ProcessStartInfo ?
As example:
ProcessStartInfo start = new ProcessStartInfo();
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.FileName = "runtime\\bin\\python\\python_mcp";
start.Arguments = "runtime\\decompile.py %*";
start.CreateNoWindow = true;
start.UseShellExecute = false;
bBuild = true;
sStatus = "Decompiling...";
Process proc = new Process();
proc.StartInfo = start;
this.Invoke((MethodInvoker)delegate { rtOut.Clear(); });
OutputMsg("========== Decompiling Binaries ==========");
this.Invoke((MethodInvoker)delegate { proc.Start(); });
while (!proc.StandardOutput.EndOfStream)
{
OutputMsg(proc.StandardOutput.ReadLine());
}
this.Invoke((MethodInvoker)delegate { proc.WaitForExit(); });
this.Invoke((MethodInvoker)delegate { proc.Close(); });
OutputMsg("========== Finished decompiling ==========");
bBuild = false;
sStatus = sIdleMessage;
but proc.StandardOutput.ReadLine() does not get any output.
The standart print() output from python is caught but not the logging one
I hope someone can help me.
Related
I am trying to implement piping behavior in C#.NET using Process and ProcessStartInfo classes. My intention is to feed the output of previous command to next command so that that command will process the input and return result. have a look into following code -
private static string Out(string cmd, string args, string inputFromPrevious)
{
string RetVal = string.Empty;
try
{
ProcessStartInfo psi = String.IsNullOrEmpty(args) ? new ProcessStartInfo(cmd) : new ProcessStartInfo(cmd, args);
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.RedirectStandardInput = string.IsNullOrEmpty(inputFromPrevious) ? false : true;
Process proc = new System.Diagnostics.Process();
proc.StartInfo = psi;
if (proc.Start())
{
if (!string.IsNullOrEmpty(inputFromPrevious))
{
proc.StandardInput.AutoFlush = true;
proc.StandardInput.WriteLine(inputFromPrevious); proc.StandardInput.WriteLine();
proc.StandardInput.Close();
}
using (var output = proc.StandardOutput)
{
Console.WriteLine("3. WAITING WAITING....."); < ---Code halts here.
RetVal = output.ReadToEnd();
}
}
proc.WaitForExit();
proc.Close();
}
catch (Exception Ex)
{
}
return RetVal; < ---This is "inputFromPrevious" to next call to same function
}
I am calling above code in loop for different commands and arguments. Is there any mistake in my code? I had looked similar as shown below but nothing worked for me as of now. Any help will be appreciated.
Piping in a file on the command-line using System.Diagnostics.Process
Why is Process.StandardInput.WriteLine not supplying input to my process?
Repeatably Feeding Input to a Process' Standard Input
I am trying to run cmd winsat -drive c programmatically
The code below is only returning "Windows System Assessment Tool" the first line of the output but is not letting the winsat run and return the rest of the output
I am looking for the entire output to be returned shown here
The code I am using is this
public string RunAndOutput(object command)
{
var procStartInfo =
new ProcessStartInfo("winsat", "/c " + "-drive c");
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
var proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
string result = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(); // Wait for everything to finish
return result;
}
You will need to wait for the process to exit using WaitForExit(), like this:
public string RunAndOutput(object command)
{
var procStartInfo =
new ProcessStartInfo("cmd", "/c " + command);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
var proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
string result = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(); // Wait for everything to finish
return result;
}
My application opens a website then runs a VBS file to do some data input. Once it's completed the data input, I want to quit the application.
In my current iteration, the VBS file executes and my C# code keeps going (quitting the web app before the data entry is completed).
Process.Start(appPath + #"external\website.url");
getAllProcesses(false);
ProcessStartInfo startInfo = new ProcessStartInfo(appPath + #"\external\UNLOCK.vbs", employeeID);
Process scriptProc = new Process();
scriptProc.StartInfo.FileName = #"cscript";
scriptProc.StartInfo.WorkingDirectory = appPath + #"external\";
scriptProc.StartInfo.Arguments = "UNLOCK.vbs " + employeeID;
scriptProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; //prevent console window from popping up
scriptProc.StartInfo.RedirectStandardError = true;
scriptProc.StartInfo.RedirectStandardInput = true;
scriptProc.StartInfo.RedirectStandardOutput = true;
scriptProc.StartInfo.ErrorDialog = false;
scriptProc.StartInfo.UseShellExecute = false;
scriptProc.Start();
scriptProc.WaitForExit(); // <-- Optional if you want program running until your script exit
Read(scriptProc.StandardOutput);
Read(scriptProc.StandardError);
while(true)
{
String completed = Console.ReadLine();
scriptProc.StandardInput.WriteLine(completed);
if(completed.CompareTo("Completed") == 0)
{
break;
}
}
if (scriptProc.HasExited)
{
getAllProcesses(true);
Application.Exit();
}
scriptProc.Close();
I want to only execute
getAllProcesses(true);
Application.Exit();
ONLY After I get output from my VBS file that says "Completed".
My VBS file has a line that says
WScript.Echo "Completed"
at the end.
Process scriptProc = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.WorkingDirectory = appPath + #"external\";
info.FileName = "Cscript.exe";
info.Arguments = "UNLOCK.vbs" + employeeID;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.WindowStyle = ProcessWindowStyle.Hidden;
scriptProc.StartInfo = info;
scriptProc.Start();
scriptProc.WaitForExit();
bool exit = false;
while (!scriptProc.StandardOutput.EndOfStream)
{
if (scriptProc.StandardOutput.ReadLine() == "Completed")
{
exit = true;
break;
}
}
if (exit == true)
{
getAllProcesses(true);
Application.Exit();
}
I have found many examples of coding on how to execute cmd.exe and execute a command, and execute even nslookup and interact, but the problem I am having is with a particular dos program that when it starts, it does not stop "outputting". here is some code and I will put a comment and the errors I get from C#
Here is how I have it setup in a more advanced way so I can receive output from the program on events
public void StartApplication(string appNameAndPath)
{
StreamReader outputStream;
Process p = new Process();
p.StartInfo.FileName = appNameAndPath;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = false;//for now just so I can see it
p.Start();
//here is my advanced example
if(advanced == true)
{
outputStream = p.StandardOutput;
DoReadOutPut();
}
else
{//here is a simple example
while (p.StandardOutput.ReadLine() != null) //this hangs here until the application exists
{
txt += (p.StandardOutput.ReadLine());
}
}
}
void DoReadOutput()
{
outputStream.BaseStream.BeginRead( readOutputBuffer, 0, readOutputBuffer.Length, new AsyncCallback( OnReadOutputCompleted ), null );
//this does sometimes fire but only with 0 bytes, on other dos programs it would say Memory read not allowed
}
void OnReadOutputCompleted( IAsyncResult result )
{
int cbRead = outputStream.BaseStream.EndRead( result );
ProcessOutput( readOutputBuffer, cbRead );
DoReadOutput();
}
private void ProcessOutput(byte[] buffer, int cbRead)
{
string text = p.StartInfo.StandardOutputEncoding.GetString(buffer, 0, 10000); //this is where it hangs until the program exits or is not writing anymore
this.Invoke((Action)delegate
{
SetTextBoxValue(text);//im doing this because im on another thread otherwise textBox1.Text - text"
});
}
I do not want to have to use API and GetText and create an engine to ReadLastLine, can anyone help me with this? I suppose you would want an example exe, creating a C# application that while(true){Console.WriteLine("bla");} would suffice as the example exe but not the exe I am having trouble with. The exe takes over the dos window and has an "old school interface"
async/await can help here....
await Exec(yourExe,parameters);
Task Exec(string exe,string args)
{
var tcs = new TaskCompletionSource<object>();
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = exe;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.Arguments = args;
var proc = Process.Start(psi);
proc.OutputDataReceived += (s, e) =>
{
this.Invoke((Action) (()=>richTextBox1.AppendText(e.Data + Environment.NewLine)));
};
proc.Exited += (s, e) => tcs.SetResult(null);
proc.EnableRaisingEvents = true;
proc.BeginOutputReadLine();
return tcs.Task;
}
You need to handle callback events to read streams:
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
Process proc = new Process();
proc.StartInfo = startInfo;
proc.ErrorDataReceived += new DataReceivedEventHandler(DataReceiveHandler);
proc.OutputDataReceived += new DataReceivedEventHandler(DataReceiveHandler);
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
Code borrowed from this post
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();