我试图将批处理文件执行的输出重定向到控制台应用程序的主窗口。
我正在调用方法来运行这样的过程:
this.runProcess("\\bar\foo\blah\", "myBatch1.bat", "bat");
被调用的方法如下:
public void runProcess(string aPath,string aName,string aFiletype)
{
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Started: {0}",DateTime.Now.ToString("dd-MMM hh:mm:ss"));
Console.WriteLine("Will try run this file {0} {1}",aPath,aName);
Console.WriteLine("File type {0}",aFiletype);
string stInfoFileName;
string stInfoArgs;
if(aFiletype == "bat")
{
stInfoFileName = @"cmd.exe";
stInfoArgs = "//c " + aName;
}
else
{ //vbs
stInfoFileName = @"cscript";
stInfoArgs = "//B " + aName;
}
this.aProcess.StartInfo.FileName = stInfoFileName;
this.aProcess.StartInfo.Arguments = stInfoArgs;
this.aProcess.StartInfo.WorkingDirectory = @aPath;
this.aProcess.StartInfo.CreateNoWindow = true;
this.aProcess.StartInfo.UseShellExecute = false;
this.aProcess.StartInfo.RedirectStandardError = true;
this.aProcess.StartInfo.RedirectStandardOutput = true;
this.aProcess.Start();
Console.WriteLine("<<<got to here");
Console.WriteLine(this.aProcess.StandardOutput.ReadToEnd());
Console.WriteLine(this.aProcess.StandardError.ReadToEnd());
this.aProcess.WaitForExit(); //<-- Optional if you want program running until your script exit
this.aProcess.Close();
Console.WriteLine("Finished: {0}",DateTime.Now.ToString("dd-MMM hh:mm:ss"));
}
为了弄清楚发生了什么,我已经为WriteLine
添加了额外的电话
"<<<got to here"
被写入控制台,然后它就会挂起而不再发生任何事情。
怀疑我的错误是非常微不足道的,因为我对这项技术的经验有限。
我做错了什么?
答案 0 :(得分:2)
好吧,你正在使用ReadToEnd()
- 这将会阻止,直到进程退出,基本上。
当您重定向标准输出和错误时,这是一个非常糟糕的主意 - 当I / O缓冲区变满时,两个应用程序都将冻结。
相反,您可能希望使用异步I / O来读取输出(并根据需要将其写入控制台 - 但您需要确保错误和输出不会相互混淆)。或者只是重定向其中一个而不是两个。
处理此问题的最简单方法是使用ErrorDataReceived
和OutputDataReceived
事件:
aProcess.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
aProcess.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
aProcess.BeginOutputReadLine();
aProcess.BeginErrorReadLine();
aProcess.WaitForExit();
除了实际工作之外,这也意味着输出会在出现时打印出来,而不是在进程退出时打印出来。
答案 1 :(得分:1)
由于您希望在现有控制台中输出子项,因此您不需要任何重定向。只需将UseShellExecute
设置为false,就不要设置CreateNoWindow
。
此代码适用于我:
using System;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
Process aProcess = new Process();
public void runProcess(string aPath, string aName, string aFiletype)
{
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Started: {0}", DateTime.Now.ToString("dd-MMM hh:mm:ss"));
Console.WriteLine("Will try run this file {0} {1}", aPath, aName);
Console.WriteLine("File type {0}", aFiletype);
string stInfoFileName;
string stInfoArgs;
if (aFiletype == "bat")
{
stInfoFileName = "cmd.exe";
stInfoArgs = "/c " + aPath + aName;
}
else
{ //vbs
stInfoFileName = "cscript";
stInfoArgs = "/B " + aPath + aName;
}
this.aProcess.StartInfo.FileName = stInfoFileName;
this.aProcess.StartInfo.Arguments = stInfoArgs;
this.aProcess.StartInfo.WorkingDirectory = aPath;
this.aProcess.StartInfo.UseShellExecute = false;
this.aProcess.Start();
Console.WriteLine("<<<got to here");
this.aProcess.WaitForExit(); //<-- Optional if you want program running until your script exit
this.aProcess.Close();
Console.WriteLine("Finished: {0}", DateTime.Now.ToString("dd-MMM hh:mm:ss"));
}
static void Main(string[] args)
{
new Program().runProcess("c:\\working\\", "test.bat", "bat");
Console.WriteLine("Exiting");
}
}
}
我取出了重定向和相关逻辑,以及设置CreateNoWindow
的行。我还在命令行中添加了aPath
,以便它可以用于UNC路径(没有驱动器号的路径),因为它们不能设置为工作目录。
答案 2 :(得分:0)
我在if(aFiletype == "bat")
之后修改了第一个选项,并且bat
文件正常运行。
public void runProcess(string aPath,string aName,string aFiletype)
{
aProcess = new Process();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Started: {0}",DateTime.Now.ToString("dd-MMM hh:mm:ss"));
Console.WriteLine("Will try run this file {0} {1}",aPath,aName);
Console.WriteLine("File type {0}",aFiletype);
string stInfoFileName;
string stInfoArgs;
if(aFiletype == "bat")
{
stInfoFileName = (@aPath + @aName);
stInfoArgs = string.Empty;
}
else
{ //vbs
stInfoFileName = @"cscript";
stInfoArgs = "//B " + aName;
}
this.aProcess.StartInfo.FileName = stInfoFileName;
this.aProcess.StartInfo.Arguments = stInfoArgs;
this.aProcess.StartInfo.WorkingDirectory = @aPath;
//new 18 june 2015//////
if(aFiletype == "bat")
{
this.aProcess.StartInfo.CreateNoWindow = true;
this.aProcess.StartInfo.UseShellExecute = false;
this.aProcess.StartInfo.RedirectStandardError = true; //<< HJ
this.aProcess.StartInfo.RedirectStandardOutput = true; //<< HJ
}
////////////////////////
this.aProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal; //.Hidden
this.aProcess.Start();
aProcessName = this.aProcess.ProcessName;
if(aFiletype == "bat")
{
this.aProcess.ErrorDataReceived += (s,e) => Console.WriteLine(e.Data);
this.aProcess.OutputDataReceived += (s,e) => Console.WriteLine(e.Data);
this.aProcess.BeginOutputReadLine();
this.aProcess.BeginErrorReadLine();
}
this.aProcess.WaitForExit();
this.aProcess.Dispose();
Console.WriteLine("Process {0} closed: {1}", this.aProcessName, DateTime.Now.ToString("dd-MMM hh:mm:ss"));
}