You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用StandardInput/Output重定向时保留应用基础功能的技术问询

问题描述

我尝试运行非GUI外部程序dsmadmc.exe,通过RedirectStandardInput和RedirectStandardOutput与TextBox进行数据交互。目前遇到两个问题:

  1. 原程序的命令提示符「SERVER1>」无法显示
  2. 分页滚动功能失效,所有输出一次性写入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:20:37