I can understand that there has been a lot of questions on this topic but none of them could really solve my problem. So here I have presented my code, and I want my mistakes to be pointed out here.
I have a program written in C# which shall call a python executable/file. The first requirement is that I have pass one argument to the python file via the input stream. This I could do. The real problem I am facing now is that, I have to see whether my python file is printing "Please enter argument_x", I have to read this output in my C# code and check if it is argument_x, then only write the argument value in the input stream. Below are the code snippets for C# and Python.
The C# code is as follows:
using System;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
//Create a new process object
Process myProcess = new Process();
//Provide the start information for the process
myProcess.StartInfo.FileName = "python.exe";
myProcess.StartInfo.Arguments = "mytestpython.py";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardOutput = true;
StreamReader myStreamReader;
StreamWriter myStreamWriter;
//Invoke the process from current process
myProcess.Start();
myStreamReader = myProcess.StandardOutput;
//Read the standard output of the spawned process.
string myString = myProcess.StandardOutput.ReadToEnd();
Console.WriteLine(myString);
if (myString.Contains("argument_x"))
{
myStreamWriter = myProcess.StandardInput;
String argument = "argument_value";
myStreamWriter.WriteLine(argument);
}
myProcess.WaitForExit();
myStreamWriter.Close();
myStreamReader.Close();
myProcess.Close();
}
}
}
The python program in mytestpython.py file looks like this:
import sys
import getpass
prompt_string = "Please enter argument_x"
if sys.stdin.isatty():
reqd_arg = getpass.getpass(prompt=prompt_string)
else:
print(prompt_string)
reqd_arg = sys.stdin.readline().rstrip()
Please help me out, as I feel I have written 90% of the code correctly with a minor mistake somewhere in between. Thanks in advance for your help.
When you do myProcess.StandardOutput.ReadToEnd();
, it tries to read to the end of the stdout of your Python program, meaning it will wait for the Python program to finish executing and close its stdout stream, which it never does because it's waiting for input from your C# program. This results in a deadlock.
ReadToEnd()
is useful when the parent process waits for child process to finish. In case of interactive process communication, you should really consider using asynchronous communications using BeginOutputReadLine
check the MSDN documentation here for help
I modified the C# code to accept CLI params and to pass the password on a prompt as follows:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
namespace Stub
{
class Program
{
static void Main(string[] args)
{
// Declare variables and initialize
string passWord = string.Empty;
string processArgs = getArguments(args); //Call getArguments method
Console.Write("Please enter the system password : ");
passWord = readPassword(); //call readPassword method
Process p = new Process();
p.StartInfo.FileName = "myexe.exe";
p.StartInfo.Arguments = processArgs;
p.StartInfo.WorkingDirectory = "my_working_directory";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
StreamWriter sw = p.StandardInput;
StreamReader sr = p.StandardOutput;
writePassword(sr, sw, "password", passWord);
sw.Close();
sr.Close();
p.WaitForExit();
p.Close();
}
static string getArguments(string[] args)
{
StringBuilder procArgs = new StringBuilder();
foreach (string arg in args)
{
procArgs.Append(arg);
procArgs.Append(" ");
}
return procArgs.ToString();
}
static void writePassword(StreamReader sr, StreamWriter sw, string keyWord, string passWord)
{
string mystring;
do
{
mystring = sr.ReadLine();
} while (!mystring.Contains(keyWord));
if (mystring.Contains(keyWord))
sw.WriteLine(passWord);
else
sw.WriteLine("\r\n");
}
static string readPassword()
{
string pass = string.Empty;
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
if (key.Key != ConsoleKey.Backspace)
{
pass +=key.KeyChar;
Console.Write("*");
}
else
{
if (pass.Length > 0)
{
pass = pass.Substring(0, (pass.Length - 1));
Console.Write("\b \b");
}
}
} while (key.Key != ConsoleKey.Enter);
return pass;
}
}
}
And then just a small modification in Python as :
import sys
import getpass
prompt_string = "Please enter password"
if sys.stdin.isatty():
reqd_arg = getpass.getpass(prompt=prompt_string)
else:
print(prompt_string)
sys.stdout.flush()
reqd_arg = sys.stdin.readline().rstrip()
And voila..that worked !!!
来源:https://stackoverflow.com/questions/10940068/interprocess-communication-between-c-sharp-and-python