0

最初的问题

如果此问题已在其他地方提出并解决,我深表歉意;我搜索了这个网站,整个谷歌都没有任何运气。

我正在尝试编写一个简单的 VB.Net Windows 窗体应用程序,以允许用户使用非常简单的 GUI 运行 Windows 文件比较程序 (fc.exe)(“浏览”按钮选择文件,复选框选择修饰符,以及输出的文本框)。

问题是每当我尝试从进程中读取标准输出或错误时,它会立即停止,并且没有任何输出。我已经通过将“createnowindow”设置为 False 并且不重定向输出或错误来验证进程参数是否正确。

为了查看进程是否实际运行,我在 proc.start 之后放置了一个“while”循环:

Do While proc.HasExited = False
textbox.AppendText(i & vbNewLine)
i += 1
Loop

如果进程正常运行,我会得到大约 80 或 90 的计数。如果我对标准输出或标准错误做任何事情,文本框只会显示初始值“0”。通过“任何东西”,我的意思是分配proc.StandardOutput.ReadToEnd给一个变量。如果我使用proc.StandardOutput.Peek,它会返回 a-1并且循环保持在 0。

我注意到,如果我只重定向输出错误(但不是两者),并且我启用该进程以打开一个新窗口,则新窗口为空并立即退出(即使我没有尝试读取重定向的在我的代码中流),而如果两者都没有被重定向,它会显示几页结果,然后退出。我不知道这是否正常,或者文件比较可执行文件是否以某种方式混合了输出和错误流以生成其输出,或者类似的事情是否可能。

一般来说,我对编码非常陌生(我已经使用 VB.net 大约一个月了,这就是我的编程经验的程度),所以我知道我的故障排除和假设可能完全不符合实际,我感谢任何人可以提供的任何帮助。事实上,我完全陷入困境,而且我的经验不足使得寻找替代品变得困难(例如,我无法弄清楚如何正确处理异步输出)。作为参考,这是我目前的笨拙代码:

Dim cmdinput As String = """" & file1path & """" & " " & """" & file2path & """"
    Dim cmdmods As String = " "
    Dim i As Integer = 0
    Dim proc As New Process
    proc.StartInfo.CreateNoWindow = True
    proc.StartInfo.UseShellExecute = False
    proc.StartInfo.FileName = "C:\Windows\System32\fc.exe"
    proc.StartInfo.Arguments = cmdinput & cmdmods
    proc.StartInfo.RedirectStandardOutput = True
    proc.StartInfo.RedirectStandardError = True
    proc.Start()
    proc.StandardOutput.ReadToEnd()

    Do While proc.HasExited = False
        scanbox.AppendText(i & vbNewLine)

        i += 1
    Loop

可能的解决方案

在 Hans Passant 指出我应该看到错误之后,如果没有其他问题,我就弄乱了我的代码并能够得到一个结果,尽管不是最优的。我没有直接运行 FC.exe,而是运行了 CMD.exe。我以前试过这个但没有运气,但那是因为 CMD.exe 不接受“fc”作为 process.startinfo.arguments。

我使用 proc.standardinput.writeline() 将“fc”传递给 cmd.exe。此时我能够读取 CMD.exe 的重定向输出。我仍然不知道为什么我不能直接读取 FC.exe,但同时这是一个很好的创可贴。如果其他人觉得需要将 GUI 添加到一个非常好的命令行可执行文件并遇到问题,这是我的代码:

Public Sub compare()
    Dim cmdinput As String = "fc " & """" & file1path & """" & " " & """" & file2path & """"
    Dim cmdmods As String = " "
    Dim proc As New Process
    proc.StartInfo.CreateNoWindow = True
    proc.StartInfo.UseShellExecute = False
    proc.StartInfo.FileName = "C:\Windows\System32\cmd.exe"
    proc.StartInfo.Arguments = cmdinput & cmdmods
    proc.StartInfo.RedirectStandardOutput = True
    proc.StartInfo.RedirectStandardError = True
    proc.StartInfo.RedirectStandardInput = True
    proc.Start()
    proc.StandardInput.WriteLine(cmdinput)
    proc.StandardInput.Close()
    scanbox.AppendText(proc.StandardOutput.ReadToEnd)
    proc.WaitForExit()
    proc.Close()
    proc.Dispose()
End Sub

我非常感谢 Hans Passant 和 Dan Verdolino 耐心地为我漫无边际的问题提供建议。一个星期以来,我一直把头撞在墙上,试图拼凑出某种方法来做到这一点。

4

2 回答 2

1

解决方案

我没有直接运行 FC.exe,而是运行了 CMD.exe。我以前试过这个但没有运气,但那是因为 CMD.exe 不接受“fc (args)”作为 process.startinfo.arguments。

我使用 proc.standardinput.writeline() 将“fc (args)”传递给 cmd.exe。此时我能够读取 CMD.exe 的重定向输出。我仍然不知道为什么我不能直接读取 FC.exe 的输出或错误,但同时这是一个很好的创可贴。如果其他人觉得需要将 GUI 添加到一个非常好的命令行可执行文件并遇到问题,这是我的代码:

Public Sub compare()
    Dim cmdinput As String = "fc " & """" & file1path & """" & " " & """" & file2path & """"
    Dim cmdmods As String = " "
    Dim proc As New Process
    proc.StartInfo.CreateNoWindow = True
    proc.StartInfo.UseShellExecute = False
    proc.StartInfo.FileName = "C:\Windows\System32\cmd.exe"
    proc.StartInfo.Arguments = cmdinput & cmdmods
    proc.StartInfo.RedirectStandardOutput = True
    proc.StartInfo.RedirectStandardError = True
    proc.StartInfo.RedirectStandardInput = True
    proc.Start()
    proc.StandardInput.WriteLine(cmdinput)
    proc.StandardInput.Close()
    scanbox.AppendText(proc.StandardOutput.ReadToEnd)
    proc.WaitForExit()
    proc.Close()
    proc.Dispose()
End Sub
于 2013-03-23T07:05:30.293 回答
0
Private Delegate Sub InvokeWithString(ByVal text As String)
Public Sub StartFC()
    Private psi As ProcessStartInfo
    Private cmd As Process

Dim CMDINPUT As String = "fc " & """" & file1path & """" & " " & """" & file2path & """"
       Dim FileToHit As String = "c:\windows\system32\fc.exe "

 psi = New ProcessStartInfo(FileToHit)
        Dim systemencoding As System.Text.Encoding = _
            System.Text.Encoding.GetEncoding(Globalization.CultureInfo.CurrentUICulture.TextInfo.OEMCodePage)

        With psi
            .Arguments = CMDINPUT 
            .UseShellExecute = False   ' Required for redirection
            .RedirectStandardError = True
            .RedirectStandardOutput = True
            .RedirectStandardInput = True
            .CreateNoWindow = True
            .StandardOutputEncoding = systemencoding  
            .StandardErrorEncoding = systemencoding
        End With

        ' EnableraisingEvents is required for Exited event
        cmd = New Process With {.StartInfo = psi, .EnableRaisingEvents = True}
        AddHandler cmd.ErrorDataReceived, AddressOf Async_Data_Received
        AddHandler cmd.OutputDataReceived, AddressOf Async_Data_Received
        AddHandler cmd.Exited, AddressOf CMD_Exited
        cmd.Start()
        pID1 = cmd.Id
        cmd.BeginOutputReadLine()
        cmd.BeginErrorReadLine()
        Me.txtInputStringIn.Select() ' textbox where you can send more commands. 
End Sub
'This event fires when process exited
 Private Sub CMD_Exited(ByVal sender As Object, ByVal e As EventArgs)
        'Me.Close()
        MessageBox.Show("Process is exited.")
    End Sub
'This part calls when Output received 
    Private Sub Async_Data_Received(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
        Me.Invoke(New InvokeWithString(AddressOf Sync_Output), e.Data)
    End Sub

    Private Sub Sync_Output(ByVal text As String)
'an output textbox will show the output of the command prompt.
        txtOutPut.AppendText(text & Environment.NewLine)
        txtOutPut.ScrollToCaret()
    End Sub
于 2013-09-13T08:00:43.040 回答