Переменные среды Process.Start() и PATH

У меня есть следующее тривиальное приложение С#, которое просто пытается запустить "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.

Ответ 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);
}

Я нашел один пара, который дал мне идею для этого решения. Из документации для Process.Start

Если у вас есть переменная пути, объявленная в вашей системе, используя кавычки, вы должен полностью квалифицировать этот путь при запуске любого процесса, найденного в этом место нахождения. В противном случае система не найдет путь. Например, если c:\mypath не находится на вашем пути, и вы добавляете его, используя котировку mark: path =% path%; "c:\mypath", вы должны полностью квалифицировать любой процесс в c:\mypath при запуске.

Как я его читал, хотя переменная PATH содержала допустимый путь, который может использовать Windows, Process.Start не может использовать его и нуждается в полном пути .

Ответ 2

Вы можете решить эту проблему, если сначала создаете ProcessStartInfo.

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

// Manipulate dictionary...

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

Вам нужно будет выяснить, как управлять PATH, чтобы он работал для вас. Но это должно решить любые проблемы, которые могут возникнуть с вашей переменной PATH.

Ответ 3

Принятый ответ неверен.

cmd.exe сначала найдет приложения с исполняемыми расширениями.

Поэтому, когда у вас есть файлы puma и puma.bat в C:\Ruby\bin\, тогда buma.bat будет иметь приоритет над puma.

Если вы запустите c:\ruby\bin\puma.bat из c:\redmine, он запустит puma с текущим рабочим каталогом c:\ruby\bin, и ваше веб-приложение будет работать.

Если вы запустите c:\ruby\bin\puma напрямую, он запустит 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