C# Process.Start() 和 PATH 环境变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12392913/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Process.Start() and PATH environment variable
提问by Reg Domaratzki
I have the following trivial C# application that simply attempts to launch "jconsole.exe", which on my machine is located in C:\Programs\jdk16\bin.
我有以下简单的 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);
}
}
}
}
If my PATH environment variable is set to
如果我的 PATH 环境变量设置为
c:\windows;c:\windows\sytem32;c:\programs\jdk16\bin
it works perfectly. However, if the PATH environment variable is set to
它完美地工作。但是,如果 PATH 环境变量设置为
c:\windows;c:\windows\sytem32;c:\programs\jdk16\bin
(note the two backslashes between "c:" and "programs"), it fails with a win32 exception.
(注意“c:”和“programs”之间的两个反斜杠),它失败并出现 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)
Interestingly, in the same command prompt where I run the .NET program and get the exception, I can simply type "jconsole.exe", and the program will start. Windows appears to have no trouble finding the executable with the double backslash in the PATH, but Process.Start() does.
有趣的是,在我运行 .NET 程序并得到异常的同一个命令提示符下,我只需键入“jconsole.exe”,程序就会启动。Windows 在 PATH 中找到带有双反斜杠的可执行文件似乎没有问题,但 Process.Start() 确实如此。
Why is the extra backslash in the PATH causing problems, and how I can get around the problem? I don't know where the executable I want to call will be located at runtime, so I'd rather rely on the PATH variable.
为什么 PATH 中额外的反斜杠会导致问题,我该如何解决这个问题?我不知道我要调用的可执行文件在运行时将位于何处,所以我宁愿依赖 PATH 变量。
采纳答案by Amith George
Not quite sure why the problem occurs. Though, I can think of one solution that works on my machine:
不太清楚为什么会出现问题。不过,我可以想到一种适用于我的机器的解决方案:
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);
}
I did find one para which gave me the idea for this solution. From the documentation for Process.Start
我确实找到了一个段落,它给了我这个解决方案的想法。来自Process.Start的文档
If you have a path variable declared in your system using quotes, you must fully qualify that path when starting any process found in that location. Otherwise, the system will not find the path. For example, if c:\mypath is not in your path, and you add it using quotation marks: path = %path%;"c:\mypath", you must fully qualify any process in c:\mypath when starting it.
如果您在系统中使用引号声明了路径变量,则在启动在该位置找到的任何进程时,您必须完全限定该路径。否则,系统将找不到路径。例如,如果 c:\mypath 不在您的路径中,并且您使用引号将其添加:path = %path%;"c:\mypath",则您必须在启动时完全限定 c:\mypath 中的任何进程。
The way I read it, even though the PATHvariable contained a valid path that Windows is able to use, Process.Startis unable to use it and needs the fully qualified path .
我阅读它的方式,即使该PATH变量包含 Windows 能够使用的有效路径,Process.Start也无法使用它并且需要完全限定的路径。
回答by Chrono
You can solve it if you first create a ProcessStartInfo.
如果您首先创建一个ProcessStartInfo.
ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe");
StringDictionary dictionary = psi.EnvironmentVariables;
// Manipulate dictionary...
psi.EnvironmentVariables["PATH"] = dictionary.Replace(@"\", @"\");
Process.Start(psi);
You'll have to find out yourself how to manipulate the PATH to let it work for you. But this should solve any issues you might have with your PATH variable.
您必须自己了解如何操作 PATH 以使其为您工作。但这应该可以解决您的 PATH 变量可能遇到的任何问题。
回答by Stefan Steiger
The accepted answer is incorrect.
接受的答案是不正确的。
cmd.exe will find applications with executable extensions first.
So when you have the files pumaand puma.batin C:\Ruby\bin\, then puma.batwill take precedence over puma.
cmd.exe 将首先查找具有可执行扩展名的应用程序。
因此,当您拥有文件puma和puma.batin 时C:\Ruby\bin\,puma.bat则将优先于puma.
If you start c:\ruby\bin\puma.batfrom c:\redmine, it will start puma with current working directory c:\ruby\bin, and your web application will work.
However, if you start c:\ruby\bin\pumadirectly, it will start puma with the current working directory in c:\redmineand will subsequently fail.
如果您c:\ruby\bin\puma.bat从开始c:\redmine,它将使用当前工作目录启动 puma c:\ruby\bin,并且您的 Web 应用程序将工作。
但是,如果c:\ruby\bin\puma直接启动,它将在当前工作目录中启动 puma,c:\redmine随后会失败。
So a corrected version looks more or less like this:
所以修正后的版本或多或少是这样的:
// 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

