我有以下简单的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”之间的两个反斜杠),它以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 :(得分:12)
不太确定问题发生的原因。虽然,我可以想到一个适用于我的机器的解决方案:
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不在您的路径中,并使用引号添加它 marks:path =%path%;“c:\ mypath”,您必须完全限定任何进程 在c:\ mypath中启动它。
我阅读它的方式,即使PATH
变量包含Windows能够使用的有效路径,Process.Start
也无法使用它,并且需要完全限定的路径。< /强>
答案 1 :(得分:4)
如果您首先创建ProcessStartInfo
,则可以解决此问题。
ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe");
StringDictionary dictionary = psi.EnvironmentVariables;
// Manipulate dictionary...
psi.EnvironmentVariables["PATH"] = dictionary.Replace(@"\\", @"\");
Process.Start(psi);
您必须自己找出如何操纵PATH让它适合您。但这应该可以解决PATH变量可能遇到的任何问题。
答案 2 :(得分:2)
接受的答案不正确。
cmd.exe将首先找到具有可执行扩展名的应用程序。
因此,当您在puma
中拥有puma.bat
和C:\Ruby\bin\
文件时,puma.bat
将优先于puma
。
如果您从c:\ruby\bin\puma.bat
启动c:\redmine
,它将启动当前工作目录c:\ruby\bin
,并且您的网络应用程序将正常运行。
但是,如果您直接启动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