使用StandardInput/Output重定向时保留应用基础功能的技术问询
问题描述
我尝试运行非GUI外部程序dsmadmc.exe,通过RedirectStandardInput和RedirectStandardOutput与TextBox进行数据交互。目前遇到两个问题:
- 原程序的命令提示符「SERVER1>」无法显示
- 分页滚动功能失效,所有输出一次性写入TextBox
我需要解决两个疑问:
- 是否可以像原程序窗口一样,使用单个TextBox同时实现输入和输出?
- 如何确保
StandardOutput输出所有内容,包括命令提示符以及输出内容超过一页时的「more... (to continue, 'C' to cancel)」提示?
当前代码
Public Class Form1 Dim WithEvents P As New Process Dim SW As System.IO.StreamWriter Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load P.EnableRaisingEvents = True Me.Text = "My title" AddHandler P.OutputDataReceived, AddressOf DisplayOutput P.StartInfo.CreateNoWindow() = True P.StartInfo.UseShellExecute = False P.StartInfo.RedirectStandardInput = True P.StartInfo.RedirectStandardOutput = True P.StartInfo.FileName = "dsmadmc.exe" P.StartInfo.Arguments = "" P.Start() P.SynchronizingObject = Me P.BeginOutputReadLine() SW = P.StandardInput SW.WriteLine() End Sub Private Sub DisplayOutput(ByVal sendingProcess As Object, ByVal output As DataReceivedEventArgs) TextBox1.AppendText(output.Data() & vbCrLf) End Sub Private Sub Textbox2_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox2.KeyPress If e.KeyChar = Chr(Keys.Return) Then SW.WriteLine(TextBox2.Text) End If End Sub Private Sub myProcess_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles P.Exited Me.Close() End Sub End Class
解决方案
1. 单个TextBox同时实现输入和输出
可以实现,需要处理几个核心点:
- 先给TextBox设置
Multiline = True、ScrollBars = Both,开启多行显示和滚动功能 - 拦截回车键,提取用户输入的命令发送给外部程序,同时保留输入记录(模拟命令行的回显效果)
- 控制光标位置,限制用户只能在文本末尾编辑,避免修改历史输出
修改后的输入处理逻辑示例:
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress If e.KeyChar = Chr(Keys.Return) Then ' 获取用户输入的最后一行命令 Dim currentText As String = TextBox1.Text Dim lastNewLineIndex As Integer = currentText.LastIndexOf(vbCrLf) Dim command As String = currentText.Substring(lastNewLineIndex + 2) ' 发送命令给外部程序 SW.WriteLine(command) ' 添加换行模拟命令行回显后的格式 TextBox1.AppendText(vbCrLf) ' 阻止默认回车行为,避免多余换行 e.Handled = True End If End Sub
同时在输出处理方法中,确保每次输出后光标移到文本末尾:
Private Sub DisplayOutput(ByVal sendingProcess As Object, ByVal output As DataReceivedEventArgs) If Not String.IsNullOrEmpty(output.Data) Then TextBox1.AppendText(output.Data & vbCrLf) ' 将光标定位到文本末尾 TextBox1.SelectionStart = TextBox1.TextLength TextBox1.ScrollToCaret() End If End Sub
2. 显示命令提示符和分页提示的问题
重定向并读取StandardError
很多CLI程序会把交互式提示(比如命令提示符、分页提示)输出到StandardError而非StandardOutput,所以需要同时重定向并监听这个流:
修改进程启动配置:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load P.EnableRaisingEvents = True Me.Text = "My title" AddHandler P.OutputDataReceived, AddressOf DisplayOutput ' 添加错误输出的处理事件 AddHandler P.ErrorDataReceived, AddressOf DisplayOutput P.StartInfo.CreateNoWindow() = True P.StartInfo.UseShellExecute = False P.StartInfo.RedirectStandardInput = True P.StartInfo.RedirectStandardOutput = True ' 开启错误输出重定向 P.StartInfo.RedirectStandardError = True P.StartInfo.FileName = "dsmadmc.exe" P.StartInfo.Arguments = "" P.Start() P.SynchronizingObject = Me P.BeginOutputReadLine() ' 开始读取错误输出流 P.BeginErrorReadLine() SW = P.StandardInput ' 移除多余的空命令发送,避免干扰程序初始化 ' SW.WriteLine() End Sub
处理分页提示的交互
当程序输出more...时,需要等待用户按下回车后再发送空行给程序,才能继续加载后续内容。可以通过标志位控制输入逻辑:
Private waitForMore As Boolean = False Private Sub DisplayOutput(ByVal sendingProcess As Object, ByVal output As DataReceivedEventArgs) If Not String.IsNullOrEmpty(output.Data) Then TextBox1.AppendText(output.Data & vbCrLf) TextBox1.SelectionStart = TextBox1.TextLength TextBox1.ScrollToCaret() ' 检测到分页提示时,设置等待标志并暂时禁用输入 If output.Data.Contains("more...") Then waitForMore = True TextBox1.Enabled = False End If End If End Sub Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress If waitForMore Then If e.KeyChar = Chr(Keys.Return) Then ' 发送回车继续分页 SW.WriteLine() waitForMore = False TextBox1.Enabled = True e.Handled = True Else ' 忽略分页等待时的其他按键 e.Handled = True End If Else If e.KeyChar = Chr(Keys.Return) Then Dim currentText As String = TextBox1.Text Dim lastNewLineIndex As Integer = currentText.LastIndexOf(vbCrLf) Dim command As String = currentText.Substring(lastNewLineIndex + 2) SW.WriteLine(command) TextBox1.AppendText(vbCrLf) e.Handled = True End If End If End Sub
额外注意事项
- 可查看
dsmadmc.exe官方文档,确认是否有禁用分页的参数(比如-noprompt类参数),能直接绕过分页交互 - 确保进程退出时释放资源,比如关闭输入流:
Private Sub myProcess_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles P.Exited SW?.Close() Me.Close() End Sub
内容的提问来源于stack exchange,提问作者Eric van Loon
相关产品推荐
相关产品推荐

