C#.Net:为什么我的Process.Start()挂起了?

我正试图从我的网络应用程序运行批处理文件,作为另一个用户。 出于某种原因,批处理文件挂起! 我可以看到“cmd.exe”在任务管理器中运行,但它只是永远坐在那里,无法被杀死,批处理文件没有运行。 这是我的代码:

SecureString password = new SecureString(); foreach (char c in "mypassword".ToCharArray()) password.AppendChar(c); ProcessStartInfo psi = new ProcessStartInfo(); psi.WorkingDirectory = @"c:\build"; psi.FileName = Environment.SystemDirectory + @"\cmd.exe"; psi.Arguments = "/q /c build.cmd"; psi.UseShellExecute = false; psi.UserName = "builder"; psi.Password = password; Process.Start(psi); 

如果您没有猜到,此批处理文件将构建我的应用程序(与执行此命令的应用程序不同的应用程序)。

Process.Start(psi); line应该立即返回,但批处理文件似乎挂起,没有执行。 有任何想法吗?

编辑:请参阅下面的答案,了解批处理文件的内容。

  • output.txt永远不会被创建。

我添加了这些行:

 psi.RedirectStandardOutput = true; Process p = Process.Start(psi); String outp = p.StandardOutput.ReadLine(); 

并在调试模式下逐步完成它们。 代码挂起在ReadLine() 。 我很难过!

我相信我找到了答案。 似乎微软凭借其无限的智慧,阻止了批处理文件在Windows Server 2003中被IIS执行.Brenden Tompkins在这里有一个解决方法:

http://codebetter.com/blogs/brendan.tompkins/archive/2004/05/13/13484.aspx

这对我不起作用,因为我的批处理文件使用IF和GOTO,但它肯定适用于简单的批处理文件。

为什么不在C#中完成所有工作而不是使用批处理文件?

我很无聊,所以我写得很快,这只是我将如何做的大纲,因为我不知道命令行开关做什么或文件路径。

 using System; using System.IO; using System.Text; using System.Security; using System.Diagnostics; namespace asdf { class StackoverflowQuestion { private const string MSBUILD = @"path\to\msbuild.exe"; private const string BMAIL = @"path\to\bmail.exe"; private const string WORKING_DIR = @"path\to\working_directory"; private string stdout; private Process p; public void DoWork() { // build project StartProcess(MSBUILD, "myproject.csproj /t:Build", true); } public void StartProcess(string file, string args, bool redirectStdout) { SecureString password = new SecureString(); foreach (char c in "mypassword".ToCharArray()) password.AppendChar(c); ProcessStartInfo psi = new ProcessStartInfo(); p = new Process(); psi.WindowStyle = ProcessWindowStyle.Hidden; psi.WorkingDirectory = WORKING_DIR; psi.FileName = file; psi.UseShellExecute = false; psi.RedirectStandardOutput = redirectStdout; psi.UserName = "builder"; psi.Password = password; p.StartInfo = psi; p.EnableRaisingEvents = true; p.Exited += new EventHandler(p_Exited); p.Start(); if (redirectStdout) { stdout = p.StandardOutput.ReadToEnd(); } } void p_Exited(object sender, EventArgs e) { if (p.ExitCode != 0) { // failed StringBuilder args = new StringBuilder(); args.Append("-s k2smtpout.secureserver.net "); args.Append("-f build@example.com "); args.Append("-t josh@example.com "); args.Append("-a \"Build failed.\" "); args.AppendFormat("-m {0} -h", stdout); // send email StartProcess(BMAIL, args.ToString(), false); } } } } 

在没有看到build.cmd的情况下,很难说出发生了什么,但是,你应该使用Path.Combine(arg1,arg2)构建路径; 这是构建路径的正确方法。

 Path.Combine( Environment.SystemDirectory, "cmd.exe" ); 

我现在不记得了,但你不必设置UseShellExecute = true吗?

“调试”它的另一种可能性是使用standardoutput然后从中读取:

 psi.RedirectStandardOutput = True; Process proc = Process.Start(psi); String whatever = proc.StandardOutput.ReadLine(); 

为了“看到”正在发生的事情,我建议你将这个过程转换为更具互动性的东西(关闭Echo off)并放置一些“打印”以查看是否真的发生了什么。 运行此命令后,output.txt文件中的内容是什么?

bmail实际上是否执行?

在之前/之前放置一些打印件以查看发生了什么。

同时在参数中添加“@”,以防万一:

 psi.Arguments = @"/q /c build.cmd"; 

它必须是非常简单的东西:)

我的猜测是build.cmd正在等待某种用户交互/回复。 如果您在结尾处使用“ > logfile.txt ”运算符记录命令的输出,则可能会帮助您找到问题。

这是build.cmd的内容:

 @echo off set path=C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;%path% msbuild myproject.csproj /t:Build > output.txt IF NOT ERRORLEVEL 1 goto :end :error bmail -s k2smtpout.secureserver.net -f build@example.com -t josh@example.com -a "Build failed." -m output.txt -h :end del output.txt 

如你所见,我小心不要输出任何东西。 这一切都发送到一个文件,如果构建失败,它会通过电子邮件发送给我。 我实际上已经将这个文件作为计划任务运行了一段时间。 我正在尝试构建一个允许我按需运行它的Web应用程序。

感谢大家的帮助到目前为止! Path.Combine提示特别有用。

我认为如果参数不正确,cmd.exe会挂起。

如果批处理正确执行,那么我就会像这样shell执行它。

 ProcessStartInfo psi = new ProcessStartInfo(); Process p = new Process(); psi.WindowStyle = ProcessWindowStyle.Hidden; psi.WorkingDirectory = @"c:\build"; psi.FileName = @"C:\build\build.cmd"; psi.UseShellExecute = true; psi.UserName = "builder"; psi.Password = password; p.StartInfo = psi; p.Start(); 

也可能是cmd.exe找不到build.cmd所以为什么不给出文件的完整路径呢?

你批量的终点是什么? 如果代码挂起在ReadLine上,那么问题可能是它无法读取批处理文件…