C#.Net:为什么我的Process.Start()挂起?
我正在尝试以另一个用户的身份从我的Web应用程序运行批处理文件。由于某种原因,批处理文件挂起!我可以看到" 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);该行立即返回,并且应该执行该操作,但是批处理文件似乎挂起,没有执行。有任何想法吗?
编辑:请参阅下面的批处理文件的内容我的答案。
- 永远不会创建output.txt。
我添加了以下几行:
psi.RedirectStandardOutput = true; Process p = Process.Start(psi); String outp = p.StandardOutput.ReadLine();
并以调试模式逐步调试它们。该代码挂在ReadLine()
上。我很沮丧!
解决方案
回答
我的猜测是build.cmd正在等待某种形式的用户交互/回复。如果在末尾使用"> logfile.txt"运算符记录命令的输出,则可能会发现问题。
回答
没有看到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();
回答
这是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 [email protected] -t [email protected] -a "Build failed." -m output.txt -h :end del output.txt
如我们所见,我小心不要输出任何内容。如果构建碰巧失败,所有这些都将发送到一个通过电子邮件发送给我的文件。实际上,我已经每天晚上将这个文件作为计划任务运行很长时间了。我正在尝试构建一个允许我按需运行的Web应用程序。
到目前为止,感谢大家的帮助! Path.Combine提示特别有用。
回答
为了"查看"正在发生的事情,我建议我们将流程转换为更具交互性的内容(关闭Echo),然后放置一些"打印件"以查看是否实际发生了任何事情。运行此命令后,output.txt文件中包含什么?
bmail是否实际执行?
在之前/之后放一些照片以查看发生了什么。
还要在参数中添加" @",以防万一:
psi.Arguments = @"/q /c build.cmd";
它必须很简单:)
回答
我认为如果参数不正确,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上挂起,则问题可能是无法读取批处理文件
回答
为什么不使用Cin而不是使用批处理文件来完成所有工作?
我很无聊,所以我写了这么快的书,这只是我将如何做的概述,因为我不知道命令行开关的作用或者文件路径。
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 [email protected] "); args.Append("-t [email protected] "); args.Append("-a \"Build failed.\" "); args.AppendFormat("-m {0} -h", stdout); // send email StartProcess(BMAIL, args.ToString(), false); } } } }
回答
我相信我已经找到了答案。看起来,Microsoft以其无尽的智慧,阻止了批处理文件在Windows Server 2003中被IIS执行。Brenden Tompkins的解决方法是:
http://codebetter.com/blogs/brendan.tompkins/archive/2004/05/13/13484.aspx
这对我不起作用,因为我的批处理文件使用IF和GOTO,但是对于简单的批处理文件肯定可以使用。