我正在使用第三方的命令行工具“sam-ba”v3.5(here免费提供)。它是一个C++ / QML命令行工具,与硬件模块接口以读取/写入数据。在大多数情况下,命令的输出被发送到Standard Error。
我有一个C# / .NET应用程序,它创建了一个Process对象来执行sam-ba工具和运行命令。执行命令的效果与预期的一样。不总是起作用的是标准错误输出的重定向。在某些命令中,C#应用程序不会接收部分或全部输出。例如,以下是直接在Windows 10命令行中使用sam-ba工具执行命令的过程:
C:\Temp\Stuff\sam-ba_3.5>sam-ba -p serial:COM5 -d sama5d3 -m version
Error: Cannot open invalid port 'COM5'
Cannot open invalid port 'COM5'
下面是来自C#应用程序的一些简单代码,用于创建Process对象,以便使用相同的命令执行sam-ba工具:
Process p = new Process
{
StartInfo = new ProcessStartInfo("sam-ba.exe", "-p serial:COM5 -d sama5d3 -m version")
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
p.Start();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
p.WaitForExit();
Console.WriteLine("Standard Out: " + output);
Console.WriteLine("Standard Error: " + error);
C#应用程序的输出:
Standard Out:
Standard Error: Cannot open invalid port 'COM5'
在这个简单的例子中,只有一个输出行被重定向到标准错误,而另一个没有。我尝试了许多不同的命令,结果是混合的。有时我得到所有的东西,有时部分输出,有时没有输出。
下面是一个python脚本(v3.8),它所做的正是C#应用程序所做的:
import subprocess
import sys
result = subprocess.run("sam-ba.exe -p serial:COM5 -d sama5d3 -m version", capture_output=True, text=True)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
这个脚本总是将正确的输出返回到标准错误。但是...当我从C#应用程序运行这个脚本来创建C# -〉python -〉sam-ba链时,我遇到了流中缺少输出的相同问题。
这使我得出两个结论:
1.这个sam-ba工具输出文本的方式有些不一样,格式,内容,......有些不一致
1.当执行外部应用程序时,由C# Process对象创建的环境有一些不同,这在直接运行外部应用程序时不会发生。否则,为什么python脚本在直接运行时会获得所有输出,而在通过C# Process对象运行时却不会?
第二个问题让我来到这里。我在寻找如何诊断这个问题的任何见解。我做错了什么,我可以在Process对象中尝试的设置,关于数据如何进入流而不被重定向出来的想法,或者是否有人以前见过这样的事情以及他们是如何解决的。
更新
拿到了sam-ba工具的源代码。C#应用程序没有捕获的输出来自QML文件。它们使用的是这个“print()'方法,我无法真正找到任何细节。C#应用程序可以捕获的输出通过信号传递回C++端,然后发送到标准错误。这反馈到我的结论#1中,它们的代码中存在不一致。
尽管如此,这可能意味着C#和QT/QML之间存在冲突,这可以解释为什么Python脚本获得QML输出,而C#应用程序没有。
1条答案
按热度按时间rm5edbpk1#
下列程式在执行行程序时使用ShellExecute而非CreateProcess。使用ShellExecute时,无法重新导向行程序的StandardOutput和/或StandardError。若要解决这个问题,StandardOutput和StandardError都会重新导向至缓存档,然后从缓存档读取数据--这似乎会产生与从cmd windows 执行时相同的输出。
注意:在下列程式码中,必须使用
%windir%\system32\cmd.exe
(例如:C:\Windows\system32\cmd.exe)。请参阅下面的用法部分。添加using语句:
using System.Diagnostics;
然后尝试以下操作:
用法:
注意:
/c C:\Temp\sam-ba_3.5\sam-ba.exe -p serial:COM5 -d sama5d3 -m version
是进程“Argument”属性的值。更新:
选项2:
下面是一个使用命名管道的解决方案。进程用于将输出重定向到命名管道而不是文件。一个进程创建一个命名管道“服务器”,侦听来自客户端的连接。然后使用
System.Diagnostics.Process
运行所需的命令,并将输出重定向到命名管道服务器。“服务器”读取输出,然后引发事件“DataReceived,”该事件将把数据返回给任何订阅者。命名管道服务器代码来自here,但我对其进行了修改。我添加了许多事件--可以订阅这些事件。我还添加了服务器在读取完数据后自行关闭的功能,方法是将“ShutdownWhenOperationComplete”设置为“true”。
创建一个名为的类:HelperNamedPipeServer.cs
帮助程序命名管道服务器.cs
接下来,我创建了一个“Helper”类,它包含启动命名管道服务器的代码,使用Process运行命令,并返回数据。有三种方法可以获取数据。它由方法返回,可以订阅“DataReceived”事件,或者一旦方法完成,数据将位于属性“Data”中。
帮助程序.cs
用法:
资源: