C# 用C语言与进程通信#

C# 用C语言与进程通信#,c#,process,C#,Process,我需要使用标准输入和标准输出与外部可执行文件(ampl.exe)通信。此exe在控制台中显示的几分钟内进行计算。它有一个提示,因此我可以在计算完成后立即使用其标准输入来连续启动计算 外部exe以以下方式启动: var myProcess = new Process(); myProcess.StartInfo = new ProcessStartInfo("ampl.exe"); myProcess.StartInfo.CreateNoWindow = true; myProcess.Start

我需要使用标准输入和标准输出与外部可执行文件(ampl.exe)通信。此exe在控制台中显示的几分钟内进行计算。它有一个提示,因此我可以在计算完成后立即使用其标准输入来连续启动计算

外部exe以以下方式启动:

var myProcess = new Process();
myProcess.StartInfo = new ProcessStartInfo("ampl.exe");
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.Start();
我使用myProcess.StandardInput和myProcess.StandardOutput(同步方式)与它进行通信

我使用标准输入启动calcul,例如:

myProcess.StandardInput.WriteLine("solve;");
我想等待solve语句结束,在文件中获取结果,准备新的计算输入文件,然后启动第二个solve

我的问题是,我现在确实知道第一次计算何时完成,即exe何时在其标准输入中等待新命令。 我找到的唯一方法是添加一个特定的display命令,然后等待它的标准输出:

    myProcess.StandardInput.WriteLine("solve;");
    myProcess.StandardInput.WriteLine("print 'calculDone';");
    string output = myProcess.StandardOutput.ReadLine();
    while (!output.Contains("calculDone"))
    {
        output = myProcess.StandardOutput.ReadLine();
    }
是否有其他方法可以避免使用此显示命令执行此操作

编辑:根据建议,我尝试了异步方式。但我仍然需要打印“CalculDone”来知道solve语句何时结束。在进程的标准输出中,我没有得到ampl.exe(即“ampl:”)的提示

AutoResetEvent eventEnd = new AutoResetEvent(false);

var myProcess = new Process();
myProcess.StartInfo = new ProcessStartInfo("ampl.exe");
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.EnableRaisingEvents = true;
myProcess.OutputDataReceived += (sender, e) =>
{
    if (e.Data == "commandDone")
    {
        eventEnd.Set();
    }
    else if (e.Data != null)
    {
        Console.WriteLine("ampl: {0}", e.Data);
    }
};

myProcess.Start();
myProcess.BeginOutputReadLine();

myProcess.StandardInput.WriteLine("solve;");
myProcess.StandardInput.WriteLine("print 'commandDone';");

eventEnd.WaitOne();

最好的选择是使用
Processs.OutputDataReceived
事件,而不是紧密的while循环。这与事件异步模式类似,您启动一个异步任务,然后等待事件回调通知您该任务已完成。异步任务的继续将进入事件处理程序。记住在事件处理程序第一次关闭时取消订阅,否则它将在您不希望它启动时启动


另一个我从未尝试过的选项是
Process.WaitForInputIdle()
方法,但我不确定这是否适用于您的特定情况。如果是这样,您就不需要向输入流写入任何内容。

许多类似这样的程序会输出一个提示(例如,
>
),如果您的程序是这样的话,您可以监视它,而不是发送额外的打印命令。当您厌倦了让应用程序与
exe进行交互通信时,然后您应该尝试一个专门为这类事情设计的
dll
(类库)。当然,除非您无法控制正在使用的
exe
。@NightOwl888:此exe没有dll,因此我别无选择。您启动的程序将缓冲其输出,在缓冲区已满、程序显式刷新缓冲区或完成并关闭stdout之前,不会显示任何内容。如果没有该程序的源代码,您将无能为力。@HansPassant:通常I/O库默认为在读取输入之前自动刷新输出。否则,交互式用户将面临与父进程相同的问题。在*nix系统上,有一个额外的因素在起作用,即stdin和stdout是否绑定到管道或tty,但是使用C#和频繁提到“EXE”表明这很可能不是*nix系统。我不认为这有什么帮助。我尝试使用标准输出的异步读取,但它并没有改变任何东西:我仍然需要打印“calculDone”,以知道calcul已经完成,exe正在等待新的输出input@NicoGDF很明显,但您并没有使用等待输入的循环进行阻塞。如果您的应用程序有一个UI,那么当前代码将冻结它,而事件方法则不会。向输入流写入时出现了什么问题?它会使您的进程崩溃吗?您可以尝试使用
WaitFroInputIdle
,尽管您可以始终通过
Task
异步运行它,但它将被阻止。这样行吗?因为exe没有图形界面,所以WaitForInputdle崩溃。我的应用程序是一个控制台应用程序。@NicoGDF订阅
进程。OutputDataReceived
事件是正确的路径。当您监视的进程终止其处理阶段时,它会输出“某物”(因为您说它不会终止)。它可以是计算完成的消息,也可以是提示。每次进程在stdout中写入内容(重定向)时,都会触发该事件。当你收到你期望的东西时,你可以采取行动。您还可以使用其进程中的进度输出(如果有的话)来更新控制台。@Jimi我编辑了它,但在使用OutputDataReceived时没有收到带有事件的提示