2012-09-12 87 views
10

我有以下的瑣碎的C#應用​​程序,它只是試圖啓動「jconsole.exe」,這在我的機器上位於C:\程序\ jdk16 \ bin中。的Process.Start()和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); 
     } 
    } 
    } 
} 

如果我的PATH環境變量設置爲

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

它完美的作品。但是,如果PATH環境變量設置爲

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

(注意兩者之間的反斜槓「C:」和「方案」),它沒有用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) 

有趣的是,當我運行.NET程序,並得到異常同一命令提示符下,我可以簡單地輸入「jconsole.exe」,程序將啓動。 Windows在PATH中使用雙反斜槓查找可執行文件似乎沒有問題,但是Process.Start()卻可以。

爲什麼是額外的反斜槓在PATH造成的問題,我怎樣才能解決這個問題呢?我不知道我要調用的可執行文件位於運行時,所以我寧願依賴PATH變量。

+0

有兩種方法來啓動一個EXE,你正在測試兩種方式。您的應用程序使用ShellExecuteEx(),命令行解釋程序使用CreateProcess()。你可以玩ProcessStartInfo.UseShellExecute屬性。沒有太多關於他們如何解釋PATH環境變量的問題,你知道如何解決這個問題。 –

回答

10

不明白爲什麼會出現這個問題。雖然,我能想到的一個解決方案,我的機器上工作的:

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

我發現它給了我這個解決方案的想法一個段。從documentation for Process.Start

如果您在使用引號在您的系統路徑變量聲明,你 必須充分開始在 位置找到任何過程,當符合該路徑。否則,系統將找不到路徑。例如, 如果c:\ mypath中是不是在你的路徑,您使用引號 引號將其添加:PATH =%PATH%; 「C:\ mypath中」,則必須完全限定任何過程 在C:\ mypath中時開始吧。

我讀的方式,即使PATH變量包含一個有效的路徑,Windows是能夠使用,Process.Start無法使用它,需要完全合格的路徑

+0

感謝您強調文檔Amith中的段落。我把它解釋爲隻影響帶引號的路徑中的條目,但我喜歡你的泛化,你不能相信Process.Start()正確使用PATH環境變量。作爲一個有趣的旁白,我嘗試設置我的路徑爲'c:\ windows \ system32; c:\ windows;「c:\ programs \ jdk16 \ bin」',並且Process.Start()能夠找到jconsole.exe任何額外的幫助。這似乎與文檔所說的有關使用PATH的Process.Start()相反,所以我現在真的不相信它。 :) –

3

你可以解決它,如果你先創建一個ProcessStartInfo

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

// Manipulate dictionary... 

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

你必須找出自己如何操作PATH讓它爲你工作。但是,這應該可以解決您在使用PATH變量時可能遇到的任何問題。

+1

更改[EnvironmentVariables屬性](http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.environmentvariables.aspx)後,必須將[UseShellExecute屬性](http ://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.useshellexecute.aspx)爲false。但是,如果UseShellExecute爲false,則必須指定[FileName屬性](http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.filename)的完全限定路徑,哪種失敗改變路徑的目的。 –

+0

然而,在UseShellExecute頁面的例子中,他們沒有給出完全限定的FileName並且使用UseShellExecute = false;我也嘗試將其設置爲false,只調用一個只能在我的PATH中找到的exe,並且它剛剛啓動。 – Chrono

3

接受的答案不正確。

cmd.exe將首先找到具有可執行擴展名的應用程序。
因此,當您在C:\Ruby\bin\中有文件pumapuma.bat時,那麼buma.bat將優先於美洲獅。

如果您從c:\redmine開始c:\ruby\bin\puma.bat,它將啓動當前工作目錄c:\ruby\bin,並且您的Web應用程序將工作。
如果您直接啓動c:\ruby\bin\puma,它將啓動當前工作目錄c:\redmine,並隨後失敗。

所以修正的版本看起來或多或少是這樣的:

// 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