#c#
#c# #путь #process.start
Вопрос:
У меня есть следующее тривиальное приложение на C #, которое просто пытается запустить «jconsole.exe «, который на моей машине находится в C:Programsjdk16bin .
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:windowssytem32;c:programsjdk16bin
это работает отлично. Однако, если переменная среды PATH установлена в
c:windows;c:windowssytem32;c:\programsjdk16bin
(обратите внимание на две обратные косые черты между «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, похоже, нет проблем с поиском исполняемого файла с двойной обратной косой чертой в ПУТИ, но процесс.Start() выполняет.
Почему дополнительная обратная косая черта в ПУТИ вызывает проблемы и как я могу обойти проблему? Я не знаю, где исполняемый файл, который я хочу вызвать, будет находиться во время выполнения, поэтому я бы предпочел полагаться на переменную PATH .
Комментарии:
1. Существует два способа запуска EXE-файла, вы тестируете оба способа. Ваше приложение использует ShellExecuteEx(), интерпретатор командной строки использует CreateProcess() . Вы можете поиграть со свойством ProcessStartInfo.UseShellExecute. Нет особого смысла беспокоиться о том, как они по-разному интерпретируют переменную среды PATH, вы знаете, как решить проблему.
Ответ №1:
Не совсем уверен, почему возникает проблема. Хотя я могу придумать одно решение, которое работает на моей машине:
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);
}
Я нашел один пункт, который дал мне идею для этого решения. Из документации для процесса.Начать
Если у вас есть переменная path, объявленная в вашей системе с использованием кавычек, вы должны полностью указать этот путь при запуске любого процесса, найденного в этом расположении. В противном случае система не найдет путь. Например, если c:mypath не находится на вашем пути, и вы добавляете его, используя кавычки: path = %path%;»c:mypath «, вы должны полностью квалифицировать любой процесс в c:mypath при его запуске.
То, как я это прочитал, несмотря PATH
на то, что переменная содержала допустимый путь, который может использовать Windows, Process.Start
не может его использовать и нуждается в полном пути .
Комментарии:
1. Спасибо, что выделили абзац из документации Amith. Я интерпретировал это как влияющее только на записи в пути с кавычками, но мне нравится ваше обобщение, что вы не можете доверять процессу. Start() для правильного использования переменной среды PATH. В качестве интересного, я попытался задать свой ПУТЬ
c:windowssystem32;c:windows;"c:programsjdk16bin"
и обработать. Start() смог найти jconsole.exe без какой-либо дополнительной помощи. Это, похоже, противоречит тому, что говорится в документах о процессе. Запуск () с использованием ПУТИ, поэтому я действительно не доверяю ему сейчас. 🙂2. Я рекомендую использовать System.IO.Path.pathSeparator для поддержки нескольких платформ. В macos разделителем путей является «:».
Ответ №2:
Вы можете решить эту проблему, если сначала создадите ProcessStartInfo
.
ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe");
StringDictionary dictionary = psi.EnvironmentVariables;
// Manipulate dictionary...
psi.EnvironmentVariables["PATH"] = dictionary.Replace(@"\", @"");
Process.Start(psi);
Вам придется самому выяснить, как управлять этим ПУТЕМ, чтобы он работал на вас. Но это должно решить любые проблемы, которые могут возникнуть у вас с вашей переменной PATH.
Комментарии:
1. После изменения свойства EnvironmentVariables вы должны установить для свойства UseShellExecute значение false . Однако, если значение UseShellExecute равно false , я должен указать полный путь для свойства FileName , что противоречит цели изменения пути.
2. Тем не менее , в самом примере на
UseShellExecute
странице они не дают полной квалификацииFileName
и использованияUseShellExecute = false;
. Я также попытался установить для него значение false и просто вызвать exe-файл, который можно найти только в моем PATH, и он просто запускается.3. я бы также рекомендовал установить ваш
Process.StartInfo.WorkingDirectory
путь к среде, который ваш .exe должен использовать
Ответ №3:
Принятый ответ неверен.
cmd.exe сначала найдет приложения с исполняемыми расширениями.
Итак, когда у вас есть файлы puma
и puma.bat
в C:Rubybin
, тогда puma.bat
они будут иметь приоритет над puma
.
Если вы начнете c:rubybinpuma.bat
с c:redmine
, он запустит puma с текущего рабочего каталога c:rubybin
, и ваше веб-приложение будет работать.
Однако, если вы запустите c:rubybinpuma
напрямую, он запустит 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}:rn{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}:rn{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