2012-09-12 34 views
10

Tengo la siguiente aplicación trivial C# que simplemente intenta iniciar "jconsole.exe", que en mi máquina se encuentra en C: \ Programs \ jdk16 \ bin.Process.Start() y variable de entorno PATH

using System; 
using System.Diagnostics; 

namespace dnet { 
    public class dnet { 
    static void Main(string[] args) { 
     try { 
     Process.Start("jconsole.exe"); 
     Console.WriteLine("Success!"); 
     } catch (Exception e) { 
     Console.WriteLine("{0} Exception caught.", e); 
     } 
    } 
    } 
} 

Si mi variable de entorno PATH se establece en

c:\windows;c:\windows\sytem32;c:\programs\jdk16\bin 

funciona perfectamente. Sin embargo, si la variable de entorno PATH se establece en

c:\windows;c:\windows\sytem32;c:\\programs\jdk16\bin 

(tenga en cuenta las dos barras invertidas entre "C" y "programas"), se produce un error con una excepción win32.

System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified 
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo) 
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo) 
at dnet.dnet.Main(String[] args) 

Curiosamente, en la misma línea de comandos cuando ejecuto el programa .NET y consigo la excepción, puedo simplemente escriba "jconsole.exe", y el programa se iniciará. Parece que Windows no tiene problemas para encontrar el ejecutable con la doble barra invertida en la RUTA, pero Process.Start() sí lo hace.

¿Por qué la barra invertida adicional en la RUTA causa problemas y cómo puedo solucionar el problema? No sé dónde se ubicará el ejecutable que quiero llamar en tiempo de ejecución, así que prefiero confiar en la variable PATH.

+0

Hay dos formas de iniciar un archivo EXE, que está probando en ambos sentidos. Su aplicación utiliza ShellExecuteEx(), el intérprete de línea de comandos usa CreateProcess(). Puede jugar con la propiedad ProcessStartInfo.UseShellExecute. No tiene mucho sentido preocuparse por cómo interpretan la variable de entorno PATH de forma diferente, ya sabe cómo solucionar el problema. –

Respuesta

10

No estoy seguro de por qué ocurre el problema. Sin embargo, se puede pensar en una solución que funciona en mi máquina:

var enviromentPath = System.Environment.GetEnvironmentVariable("PATH"); 

Console.WriteLine(enviromentPath); 
var paths = enviromentPath.Split(';'); 
var exePath = paths.Select(x => Path.Combine(x, "mongo.exe")) 
        .Where(x => File.Exists(x)) 
        .FirstOrDefault(); 

Console.WriteLine(exePath); 

if (string.IsNullOrWhiteSpace(exePath) == false) 
{ 
    Process.Start(exePath); 
} 

Lo que encontrar un párrafo que me dio la idea para esta solución. Desde el documentation for Process.Start

Si tiene una variable de ruta declarada en el sistema mediante cotizaciones, que debe calificar plenamente ese camino al iniciar cualquier proceso que se encuentra en ubicación. De lo contrario, el sistema no encontrará la ruta. Por ejemplo, si c: \ mypath no está en su ruta, y lo agrega usando comillas marcas: ruta =% ruta%; "c: \ mypath", debe calificar completamente cualquier proceso en c: \ mypath cuando comenzando.

La forma en que lo leí, a pesar de que la variable PATH contenía una ruta válida que Windows es capaz de utilizar, Process.Start es incapaz de usarlo y necesita la ruta completa .

+0

Gracias por destacar el párrafo de los documentos Amith. Lo interpreté como que solo afecta las entradas en la ruta con comillas, pero me gusta su generalización de que no puede confiar en Process.Start() para usar la variable de entorno PATH correctamente. Como un aspecto interesante, intenté configurar mi ruta a 'c: \ windows \ system32; c: \ windows;" c: \ programs \ jdk16 \ bin "', y Process.Start() fue capaz de encontrar jconsole.exe sin cualquier ayuda extra Esto parece contrario a lo que dicen los documentos, sobre Process.Start() usando el PATH, así que realmente no confío en él ahora. :) –

3

Puede resolverlo si primero crea un ProcessStartInfo.

ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe"); 
StringDictionary dictionary = psi.EnvironmentVariables; 

// Manipulate dictionary... 

psi.EnvironmentVariables["PATH"] = dictionary.Replace(@"\\", @"\"); 
Process.Start(psi); 

Tendrá que descubrir cómo manipular la RUTA para que funcione. Pero esto debería resolver cualquier problema que pueda tener con su variable PATH.

+1

Después de cambiar la propiedad [EnvironmentVariables] (http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.environmentvariables.aspx), debe establecer la propiedad [UseShellExecute] (http : //msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.useshellexecute.aspx) a falso. Sin embargo, si UseShellExecute es falso, debo especificar la ruta de acceso completa para [propiedad FileName] (http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.filename), que tipo de derrotas el propósito de cambiar el camino. –

+0

Sin embargo, en el mismo ejemplo en la página 'UseShellExecute' no dan un' FileName' completamente calificado y usan 'UseShellExecute = false;'. También he intentado configurarlo en falso y simplemente llamar a un exe que solo se puede encontrar en mi PATH y simplemente comienza. – Chrono

3

La respuesta aceptada no es correcta.

cmd.exe primero encontrará las aplicaciones con extensiones ejecutables.
Así que cuando tenga los archivos puma y puma.bat en C:\Ruby\bin\, entonces buma.bat tendrá prioridad sobre puma.

Si inicia c:\ruby\bin\puma.bat desde c:\redmine, se iniciará puma con el directorio de trabajo actual c:\ruby\bin, y su aplicación web funcionará.
Si inicia c:\ruby\bin\puma directamente, se iniciará puma con el directorio de trabajo actual en c:\redmine y posteriormente fallará.

Así que una versión corregida se ve más o menos así:

// FindAppInPathDirectories("ruby.exe"); 
public string FindAppInPathDirectories(string app) 
{ 
    string enviromentPath = System.Environment.GetEnvironmentVariable("PATH"); 
    string[] paths = enviromentPath.Split(';'); 

    foreach (string thisPath in paths) 
    { 
     string thisFile = System.IO.Path.Combine(thisPath, app); 
     string[] executableExtensions = new string[] { ".exe", ".com", ".bat", ".sh", ".vbs", ".vbscript", ".vbe", ".js", ".rb", ".cmd", ".cpl", ".ws", ".wsf", ".msc", ".gadget" }; 

     foreach (string extension in executableExtensions) 
     { 
      string fullFile = thisFile + extension; 

      try 
      { 
       if (System.IO.File.Exists(fullFile)) 
        return fullFile; 
      } 
      catch (System.Exception ex) 
      { 
       Log("{0}:\r\n{1}", 
        System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture) 
        , "Error trying to check existence of file \"" + fullFile + "\"" 
       ); 

       Log("Exception details:"); 
       Log(" - Exception type: {0}", ex.GetType().FullName); 
       Log(" - Exception Message:"); 
       Log(ex.Message); 
       Log(" - Exception Stacktrace:"); 
       Log(ex.StackTrace); 
      } // End Catch 

     } // Next extension 

    } // Next thisPath 


    foreach (string thisPath in paths) 
    { 
     string thisFile = System.IO.Path.Combine(thisPath, app); 

     try 
     { 
      if (System.IO.File.Exists(thisFile)) 
       return thisFile; 
     } 
     catch (System.Exception ex) 
     { 
      Log("{0}:\r\n{1}", 
       System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture) 
       , "Error trying to check existence of file \"" + thisFile + "\"" 
      ); 

      Log("Exception details:"); 
      Log(" - Exception type: {0}", ex.GetType().FullName); 
      Log(" - Exception Message:"); 
      Log(ex.Message); 
      Log(" - Exception Stacktrace:"); 
      Log(ex.StackTrace); 
     } // End Catch 

    } // Next thisPath 

    return app; 
} // End Function FindAppInPathDirectories 
Cuestiones relacionadas