Может ли Process.Start () учитывать системный PATH? - PullRequest
6 голосов
/ 04 ноября 2011

Я некоторое время искал и экспериментировал с этим, но мне не повезло.

Я пытаюсь создать консольную программу для автоматизации некоторых задач, которые я не мог бы сделать с помощьюBAT файл.Я хочу вызвать "signcode.exe" из Windows SDK, папку bin со всеми инструментами в моей системной переменной PATH, и я могу вызвать "signcode" из любого места, но Process.Start игнорирует путь.

Текущий код:

System.Diagnostics.Process sign = new System.Diagnostics.Process();
sign.StartInfo.FileName         = signCommand.Substring(0, signCommand.IndexOf(' '));  // signtool.exe
sign.StartInfo.Arguments        = signCommand.Substring(signCommand.IndexOf(' ') + 1); // /sign /a file1 file2

// sign.StartInfo.EnvironmentVariables["Path"] = Environment.GetEnvironmentVariable("PATH");  // This doesn't work either
sign.StartInfo.UseShellExecute              = false;
sign.StartInfo.RedirectStandardOutput       = true;
sign.StartInfo.RedirectStandardError        = true;

sign.Start();  // Throws Win32Exception - The system cannot find the file specified

Я подтвердил, что StartInfo.EnvironmentVariables ["Path"] соответствует моему системному пути и содержит папку Windows SDK.Установка его вручную также не работает.

Я даже пытался установить TempPath, как показано на странице MSDN для EnvironmentVariables Property , но это тоже не сработало.Интересно, почему вы могли бы установить это, если это не имеет никакого эффекта.

Если System.Diagnostics.Process не может использовать путь, есть ли другие функции, которые я мог бы использовать?Я также хотел бы видеть вывод команды в моем консольном приложении.

Вот некоторые дополнительные значения отладки:

Console.WriteLine("Sign Filename = '{0}'", sign.StartInfo.FileName);
Sign Filename = 'signtool.exe'

Console.WriteLine("Sign Arguments = '{0}'", sign.StartInfo.Arguments);
Sign Arguments = '/sign /f C:\Visual Studio\Projects\MGInsight\MGInsight\APPARENTINC.pfx /t http://timestamp.comodoca.com/authenticode "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\MGInsight.exe" "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\XPXScanner.dll" "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\NetworkCalculations.dll"'

Console.WriteLine("Sign Path = '{0}'", sign.StartInfo.EnvironmentVariables["Path"]);
Sign Path = 'C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;"C:\Program Files\Intel\WiFi\bin\";"C:\Program Files\Common Files\Intel\WirelessCommon\";"C:\Program Files (x86)\cwRsync\bin";"C:\Program Files (x86)\Git\cmd";"C:\Program Files (x86)\Git\bin";"C:\Program Files (x86)\Zend\ZendServer\bin";"C:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\bin";"C:\Program Files\Java\jre6\bin";"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\";"C:\Program Files\Microsoft Windows Performance Toolkit\";C:\MinGW\bin;"C:\Program Files (x86)\Microsoft\ILMerge";"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin";C:\Program Files (x86)\Nmap'

Путь "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin" - это то, где signtool.exeи я могу запустить его из командной строки, просто набрав signtool, но если я запускаю это приложение из того же приглашения, оно не регистрирует этот путь.

Ответы [ 7 ]

14 голосов
/ 04 октября 2012

Добавление к ответу mhutch: оно действительно учитывает PATH, но я заметил, что на самом деле вам нужно перезапустить Visual Studio, чтобы получить любые изменения пути.Это подлый вид.

5 голосов
/ 04 ноября 2011

Я почти уверен, что Process.Start уважает PATH.

  • Вы уверены, что ваше значение signCommand правильное?
  • Указано ли значение каталога в PATH с использованием кавычек? В документах указано, что такие значения не будут соблюдаться.

Обратите внимание, что FileName также может быть полным путем к исполняемому файлу.

2 голосов
/ 08 ноября 2012

Если вы недавно обновили PATH, обязательно перезапустите Visual Studio. Переменные среды загружаются при запуске Visual Studio. Обратите внимание, что это относится к выполнению режима DEBUG.

2 голосов
/ 04 ноября 2011

Ну, я думаю, проблема была в том, что сказал mhutch из документации MSDN:

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.

Сначала я это видел, но это казалось странным, поэтому я не обращал на это внимания. Не уверен, почему это так, но, похоже, так.

Я попытался скопировать signtool.exe в C: \ sign \ tool \ bin и добавил это к моему пути, а затем мой код сработал, так что я думаю, потому что у меня есть кавычки в этом пути из-за пробелов, я SOL и придется вручную искать путь для Windows SDK, если только нет способа добавить что-то с пробелами в путь без кавычек.

1 голос
/ 04 ноября 2011

Имя файла StartInfo фактически является полным путем к исполняемому файлу

Например, на обертке у меня для x264 это выглядит так:

x264Start.FileName = Directory.GetCurrentDirectory() + @"\Tools\x264\x264x86-r1995.exe";

Я бы проверил код, добавив в него команду try {}, catch {} и записав фактическое имя файла, которое вы пытаетесь вызвать в отладке, если у вас есть ошибка.

В противном случае добавьте что-то вроде следующего:

    if (File.exists(sign.FileName))
    {
        sign.Start();
    }
    else
    {
        Console.WriteLine("Can't find {0}", sign.FileName);
        throw new Exception("File doesn't exist");
    }

EDIT: добавлен полный пример - он ищет CCleaner, а затем запускает его с ключом "/ AUTO". Только что протестировано и отлично работает.

        // detect if 64-bit system
        string programFiles = "";
        if (Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE").Contains("64"))
        {
            Console.WriteLine("#info# x64 detected");
            programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
        }
        else
        {
            Console.WriteLine("#info# x86 detected");
            programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
        }

        // search
        string[] dirs = Directory.GetDirectories(programFiles, "CCleaner", SearchOption.AllDirectories);
        string[] exes = Directory.GetFiles(programFiles, "CCleaner64.exe", SearchOption.AllDirectories);

        //debug only
        foreach (string s in dirs)
        {
            Console.WriteLine(s);
        }

        foreach (string s in exes)
        {
            Console.WriteLine(s);
        }

        // access directly
        ProcessStartInfo CCleaner = new ProcessStartInfo(exes[0], "/AUTO");
        Process.Start(CCleaner);
1 голос
/ 04 ноября 2011
0 голосов
/ 04 ноября 2011

Ваш код, кажется, учитывает путь для меня.

Трудно сказать, что может быть не так в вашем случае, но вы можете попробовать выполнить команду через cmd.exe:

sign.StartInfo.FileName = "cmd";
sign.StartInfo.Arguments = "/c signtool.exe ...";
...