2008-08-29 11 views
12

Estoy tratando de ejecutar un archivo por lotes, como otro usuario, desde mi aplicación web. Por alguna razón, ¡el archivo por lotes se cuelga! Puedo ver que "cmd.exe" se ejecuta en el administrador de tareas, pero permanece ahí para siempre, no se puede eliminar y el archivo por lotes no se está ejecutando. Aquí está mi código:C# .Net: ¿Por qué se cuelga mi Process.Start()?

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); 

Si no adivinar, este archivo por lotes se basa mi solicitud (una aplicación diferente a la que está ejecutando este comando).

El Process.Start (psi); la línea devuelve inmediatamente, como debería, pero el archivo por lotes simplemente parece bloquearse, sin ejecutar. ¿Algunas ideas?

EDIT: Consulte mi respuesta a continuación para conocer el contenido del archivo por lotes.

  • El archivo output.txt nunca se crea.

que añaden estas líneas:

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

y dio un paso a través de ellos en modo de depuración. El código se cuelga en el ReadLine(). ¡Estoy perplejo!

+0

¿Puedes publicar el código de tu archivo de proceso por lotes e intentar emitir ecos desde tu archivo por lotes para que veas que está comenzando? –

Respuesta

5

Creo que he encontrado la respuesta. Parece que Microsoft, en toda su infinita sabiduría, ha bloqueado archivos por lotes de ser ejecutado por IIS en Windows Server 2003. Brenden Tompkins tiene un trabajo en torno aquí:

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

Eso no va a funcionar para mí , porque mi archivo por lotes usa IF y GOTO, pero definitivamente funcionaría para archivos por lotes simples.

0

Mi conjetura sería que el build.cmd está esperando algún tipo de interacción con el usuario/respuesta. Si registra la salida del comando con el operador "> logfile.txt" al final, podría ayudarlo a encontrar el problema.

2

Sin ver la build.cmd que es difícil saber lo que está pasando, sin embargo, se debe construir la ruta utilizando Path.Combine (arg1, arg2); Es la forma correcta de construir un camino.

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

No recuerdo ahora pero ¿no tiene que establecer UseShellExecute = true?

1

Otra posibilidad de "depuración" que es usar StandardOutput y luego leer de él:

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

Aquí está el contenido de 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 

Como se puede ver, I' m cuidado de no dar salida a nada. Todo va a un archivo que me es enviado por correo electrónico si la compilación falla. De hecho, he estado ejecutando este archivo como una tarea programada todas las noches desde hace bastante tiempo. Intento crear una aplicación web que me permita ejecutarla bajo demanda.

Gracias por la ayuda de todos hasta ahora! La sugerencia de Path.Combine fue particularmente útil.

1

Para "ver" lo que está pasando, le sugiero que transforme el proceso en algo más interactivo (apague Echo) y ponga algunas "impresiones" para ver si algo realmente está sucediendo. ¿Qué hay en el archivo output.txt después de ejecutar esto?

¿El BMail ejecuta realmente?

poner un poco de impresiones antes/después de ver lo que está pasando.

También añadir "@" para los argumentos, por si acaso:

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

Tiene que ser algo muy sencillo :)

0

Creo cmd.exe se bloquea si los parámetros son incorrectos.

Si el lote se ejecuta correctamente, entonces simplemente lo ejecutaría de esta manera.

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(); 

También podría ser que cmd.exe simplemente no puede encontrar build.cmd ¿por qué no dar la ruta completa al archivo?

0

¿Cuáles son las líneas finales de su lote? Si el código se bloquea en ReadLine, entonces el problema podría ser que no puede leer el archivo por lotes ...

3

¿Por qué no hacer todo el trabajo en C# en lugar de usar archivos por lotes?

Estaba aburrido, así que escribí esto muy rápido, es solo un resumen de cómo lo haría ya que no sé lo que hacen los modificadores de línea de comandos o las rutas de archivos.

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); 
      } 
     } 
    } 
} 
Cuestiones relacionadas