代码之家  ›  专栏  ›  技术社区  ›  Josh Hinman

C.NET:为什么我的process.start()挂起?

  •  13
  • Josh Hinman  · 技术社区  · 16 年前

    我正在尝试以另一个用户的身份从我的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() . 我被难住了!

    9 回复  |  直到 9 年前
        1
  •  5
  •   Josh Hinman    16 年前

    我相信我找到了答案。微软似乎以其无穷的智慧阻止了在WindowsServer2003中由IIS执行的批处理文件。布伦登·汤普金斯在这附近有一项工作:

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

    这对我来说不起作用,因为我的批处理文件使用if和goto,但它绝对适用于简单的批处理文件。

        2
  •  3
  •   sieben    16 年前

    为什么不在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);
                }
            }
        }
    }
    
        3
  •  2
  •   Martin Marconcini    16 年前

    但是,如果看不到build.cmd,就很难知道发生了什么,应该使用path.combine(arg1,arg2)构建路径;这是构建路径的正确方法。

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

    我现在不记得了,但你不需要设置useShellExecute=true吗?

        4
  •  1
  •   Biri    16 年前

    “调试”的另一种可能性是使用标准输出,然后从中读取:

    psi.RedirectStandardOutput = True;
    Process proc = Process.Start(psi);
    String whatever = proc.StandardOutput.ReadLine();
    
        5
  •  1
  •   Martin Marconcini    16 年前

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

    bmail是否实际执行?

    在后面/前面印上一些照片,看看发生了什么事。

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

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

    必须是非常简单的事情:)

        6
  •  0
  •   Espo    16 年前

    我猜build.cmd正在等待某种用户交互/回复。如果将命令的输出记录为“ >日志文件 “最后是操作员,它可能会帮助您找到问题所在。

        7
  •  0
  •   Josh Hinman    16 年前

    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应用程序。

    谢谢大家的帮助!路径。组合提示特别有用。

        8
  •  0
  •   sieben    16 年前

    如果参数不正确,我认为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,为什么不给出文件的完整路径呢?

        9
  •  0
  •   Martin Marconcini    16 年前

    你们一批的最后几行是什么?如果代码挂在readline上,那么问题可能是它无法读取批处理文件。