Process.Start()和PATH环境变量

我有以下简单的C#应用​​程序,它只是尝试启动“jconsole.exe”,它在我的机器上位于C:\ Programs \ jdk16 \ bin中。

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:”和“program”之间的两个反斜杠),它以win32exception失败。

 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程序并获得exception的同一命令提示符中,我只需键入“jconsole.exe”,程序就会启动。 Windows似乎可以在PATH中使用双反斜杠查找可执行文件,但Process.Start()可以。

为什么PATH中的额外反斜杠会导致问题,以及我如何解决问题? 我不知道我想调用的可执行文件在运行时的位置,所以我宁愿依赖PATH变量。

不太确定为什么会出现问题。 虽然,我可以想到一个适用于我的机器的解决方案:

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

我找到了一个让我想到这个解决方案的段落。 从Process.Start的文档

如果在系统中使用引号声明了路径变量,则必须在启动该位置中找到的任何进程时完全限定该路径。 否则,系统将找不到路径。 例如,如果c:\ mypath不在您的路径中,并且您使用引号添加它:path =%path%;“c:\ mypath”,则必须在启动它时完全限定c:\ mypath中的任何进程。

我读它的方式,即使PATH变量包含Windows能够使用的有效路径, Process.Start也无法使用它并且需要完全限定的路径

如果您首先创建ProcessStartInfo ,则可以解决此问题。

 ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe"); StringDictionary dictionary = psi.EnvironmentVariables; // Manipulate dictionary... psi.EnvironmentVariables["PATH"] = dictionary.Replace(@"\\", @"\"); Process.Start(psi); 

你必须找到自己如何操纵PATH让它适合你。 但这应该可以解决您的PATH变量可能遇到的任何问题。

接受的答案是不正确的。

cmd.exe将首先找到具有可执行扩展名的应用程序。
所以当你在C:\Ruby\bin\有文件pumapuma.bat时, buma.bat将优先于puma。

如果从c:\redmine启动c:\ruby\bin\puma.bat ,它将使用当前工作目录c:\ruby\bin启动puma,并且您的Web应用程序将起作用。
如果直接启动c:\ruby\bin\puma ,它将使用c:\redmine的当前工作目录启动puma,然后将失败。

所以修正后的版本或多或少看起来像这样:

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