在 C# Winforms 应用程序中嵌入 CMD 终端
Posted
技术标签:
【中文标题】在 C# Winforms 应用程序中嵌入 CMD 终端【英文标题】:Embedding a CMD terminal in a C# Winforms application 【发布时间】:2015-10-12 10:37:48 【问题描述】:我打算做的是构建一个应用程序,除其他外,它将像某些 IDE 一样嵌入一个命令行(我觉得这非常有用)。
这是我目前的代码,请注意这是一个 Winforms 项目:
public partial class Form1 : Form
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
public Form1()
InitializeComponent();
private void Form1_Load(object sender, EventArgs e)
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.UseShellExecute = false;
info.CreateNoWindow = true;
p.StartInfo = info;
p.Start();
private void button1_Click(object sender, EventArgs e)
using(StreamWriter sw = p.StandardInput)
if(sw.BaseStream.CanWrite)
sw.WriteLine(textBox1.Text);
textBox2.Text = p.StandardOutput.ReadToEnd();
textBox3.Text = p.StandardError.ReadToEnd();
p.WaitForExit();
如您所见,有 3 个文本框和一个按钮:
textbox1 用于输入命令 textbox2 用于标准输出 textbox3 用于标准错误关于我的问题:
我只能输入一个命令,因为执行后,我的CMD窗口消失了。我知道它消失了,因为我设置了info.CreateNoWindow = false;
,它确实消失了,如果我尝试输入另一个命令,我会得到一个异常。
我将如何继续保持我的 CMD 窗口“活动”,以便我可以随心所欲地使用它?简而言之,我想真正模仿 CMD 行为。
如果有不清楚的地方,请随时询问更多信息。
额外信息/我尝试了什么:
我尝试添加info.Attributes = "/K";
,因为我知道/K
应该让CMD 保持活动状态。我还读到 p.WaitForExit();
应该让 CMD 保持活动状态,但据我所知,这只是为了读取输出。不用说,我不需要它,因为我已经重定向了它的输出。这些解决方案都不起作用,但我完全有可能以错误的方式使用它们。
我需要该进程处于活动状态,这样我就可以使用cd
轻松导航并在需要时执行一系列命令,例如在访问ftp
或mysql
时。我知道我可以使用参数解决这两个示例,但不适用于每个应用程序。简而言之,每次都产生一个新进程不是我想要的。我希望该 CMD 界面始终处于启动状态。
cmd进程在
之后死掉using(StreamWriter sw = p.StandardInput)
if(sw.BaseStream.CanWrite)
sw.WriteLine(textBox1.Text);
但我无法确定原因。
【问题讨论】:
using
语句导致 p.StandardInput
被释放(sw
只是对它的引用)。不要那样做 - 改为处理 p
(当您不再需要它时)。
@PieterWitvoet 谢谢你的回答。所以基本上当我离开using
范围时 p 会被处理掉?如果没有 using
语句,我将如何继续使用 StreamWriter?我尝试在 Form1_Load
方法中声明 StreamWriter 并随后访问输出 p.StandardOutput
,但我的应用程序挂起,没有任何异常。能详细点吗?
无论你是什么using
都会在using
块的末尾处理 - 因此每次输入命令时,您的代码都会处理进程的标准输入。您实际上是在处理对象的一部分并期望它像以前一样继续工作。只需删除 using
声明即可。 sw
不是您负责的新流编写器 - 它是对 p.StandardInput
的引用。处理 p
将负责为您处理这些流编写器。
@PieterWitvoet 在您撰写最后一条评论时,我一直在尝试使用没有 using
块的 StreamWriter。调试器清楚地显示命令已发送到进程,但我的应用程序在尝试读取输出时挂起,例如textBox2.Text = p.StandardOutput.ReadToEnd();
。不用说,我的应用程序没有输出。不过有趣的是:如果我手动关闭 CMD 窗口(生成的进程),我的应用程序会收到输出。但自从我关闭它后,我不能再使用这个过程了。你知道为什么会这样吗?
我假设ReadToEnd
挂起,因为流没有结束。尝试在阅读内容之前先查看信息流。
【参考方案1】:
CMD 控制台提供的是执行预定义函数的接口(在 System32 或 %PATH% 中)。 Process 类也有同样的能力,你可以做的是当用户输入命令文本并在 textbox2 中按回车键(可以是多行,黑背景,白文本)你可以通过命令文本到 Process p = new Process();
并附加结果,使其看起来像单个 cmd 会话。现在在传递整个命令文本之前,我们需要分隔参数(如果有的话),这是出现在第一个空格之后的文本。示例:
SHUTDOWN /S /T 10
其中 Shutdown 将是文件名,而 /S /T 10 将是参数。
在执行设置ProcessStartInfo的默认目录之前:-
_processStartInfo.WorkingDirectory = @"%Path%";
否则默认为 System32 文件夹。
【讨论】:
这实际上是一个想法,我不久前也在 C++ 应用程序中考虑并实现了它。不幸的是,它只是真实事物的影子,一种模拟,一种解决方法。不是一个实际的解决方案。这正是我在 C# 中重写类似应用程序的原因。但感谢您的意见,我将保留此作为最后的手段。以上是关于在 C# Winforms 应用程序中嵌入 CMD 终端的主要内容,如果未能解决你的问题,请参考以下文章
在 Winforms-Application 中嵌入的 Unity-Application 上调用函数 [重复]
可以将 WinForms 嵌入到 VCL Delphi 应用程序中吗?
在 C# (WinForms) 中拦截应用程序中所有控件的单击事件