2012-09-12 11 views
10

Mam następujące trywialne aplikacji C#, która po prostu próbuje uruchomić "jconsole.exe", który na moim komputerze znajduje się w C: \ Programs \ jdk16 \ bin.Zmienna środowiskowa Process.Start() i 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); 
     } 
    } 
    } 
} 

Jeśli moja zmienna środowiskowa PATH jest ustawiona na

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

działa idealnie. Jednakże, jeśli zmienna środowiskowa PATH jest ustawiona na

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

(zwrócić uwagę na dwie backslashy pomiędzy „C:” i „programy”), to nie z wyjątkiem 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) 

Co ciekawe, w tym samym wierszu polecenia, gdzie mogę uruchomić program .NET i uzyskać wyjątek, mogę po prostu wpisać „jconsole.exe”, a program zostanie uruchomiony. Wygląda na to, że system Windows nie ma problemu ze znalezieniem pliku wykonywalnego z podwójnym odwróconym ukośnikiem w zmiennej PATH, ale funkcja Process.Start() działa.

Dlaczego dodatkowy ukośnik odwrotny w PATH powoduje problemy i jak mogę obejść problem? Nie wiem, gdzie plik wykonywalny, który chcę wywołać, będzie umiejscowiony w czasie wykonywania, więc wolałbym polegać na zmiennej PATH.

+0

Istnieją dwa sposoby, aby uruchomić EXE, testujesz obie strony. Twoja aplikacja używa ShellExecuteEx(), interpreter wiersza poleceń używa CreateProcess(). Możesz grać z właściwością ProcessStartInfo. UseShellExecute. Nie ma sensu martwić się o to, jak inaczej interpretują zmienną środowiskową PATH, wiesz, jak rozwiązać problem. –

Odpowiedz

10

Nie do końca wiadomo, dlaczego występuje problem. Choć mogę myśleć jedno rozwiązanie, które działa na moim komputerze:

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

znalazłem jeden para, która dała mi pomysł dla tego rozwiązania. Z documentation for Process.Start

Jeśli masz zmienna ścieżka zadeklarowane w systemie za pomocą cytatów, ty muszą w pełni zakwalifikować tę ścieżkę podczas uruchamiania dowolnego procesu znaleziony w tym lokalizacji. W przeciwnym razie system nie znajdzie ścieżki. Na przykład: , jeśli c: \ mypath nie znajduje się na Twojej ścieżce i dodajesz je za pomocą cudzysłowu znaków: ścieżka =% ścieżka%; "c: \ mójpath", musisz w pełni zakwalifikować dowolny proces w c: \ mypath, gdy zaczynając to.

Sposób czytałem go, choć zmienna PATH zawierały prawidłową ścieżkę, że Windows jest w stanie wykorzystać, Process.Start jest w stanie go używać i musi ścieżkę pełną .

+0

Dzięki za wyróżnienie akapitu od docs Amith. Zinterpretowałem to jako wpływające tylko na wpisy w ścieżce z cytatami, ale podoba mi się twoja generalizacja, której nie można zaufać Process.Start(), aby poprawnie używać zmiennej środowiskowej PATH. Jako ciekawostkę, próbowałem ustawić moją ścieżkę do 'c: \ windows \ system32; c: \ windows;" c: \ program \ jdk16 \ bin "', a Process.Start() był w stanie znaleźć jconsole.exe bez jakakolwiek dodatkowa pomoc. Wydaje się to sprzeczne z tym, co mówią doktorzy, o Process.Start() przy użyciu PATH, więc naprawdę nie ufam teraz. :) –

3

Możesz go rozwiązać, jeśli najpierw utworzysz ProcessStartInfo.

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

// Manipulate dictionary... 

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

Musisz się sam dowiedzieć, jak manipulować ścieżką, aby działała prawidłowo. Ale powinno to rozwiązać wszelkie problemy, które możesz mieć ze zmienną PATH.

+1

Po zmianie właściwości [EnvironmentVariables] (http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.environmentvariables.aspx), musisz ustawić właściwość [UseShellExecute] (http : //msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.useshellexecute.aspx) na false. Jeśli jednak UseShellExecute ma wartość false, muszę podać pełną ścieżkę do właściwości [nazwa_pliku] (http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.filename), która to rodzaj porażek cel zmiany ścieżki. –

+0

Jednak w tym samym przykładzie na stronie 'UseShellExecute' nie podają w pełni kwalifikowanego' FileName' i używają 'UseShellExecute = false;'. Próbowałem również ustawić to na false i po prostu wywołanie exe, które można znaleźć tylko w mojej PATH i to po prostu zaczyna. – Chrono

3

Przyjęta odpowiedź jest nieprawidłowa.

cmd.exe znajdzie najpierw aplikacje z rozszerzeniami wykonywalnymi.
Tak więc, jeśli masz pliki puma i puma.bat w C:\Ruby\bin\, wówczas buma.bat będzie mieć pierwszeństwo przed puma.

Jeśli uruchomisz c:\ruby\bin\puma.bat z c:\redmine, rozpocznie się puma z bieżącym katalogiem roboczym c:\ruby\bin, a twoja aplikacja internetowa będzie działać.
Bezpośrednio po uruchomieniu c:\ruby\bin\puma uruchomi puma z bieżącym katalogiem roboczym pod numerem c:\redmine, a następnie zakończy się niepowodzeniem.

Więc wersja poprawiona wygląda mniej więcej tak:

// 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 
Powiązane problemy