Can Process.Start() take the system PATH into account?

会有一股神秘感。 提交于 2019-12-23 09:07:13

问题


I've been searching and experimenting for a while with this, but I have had no luck.

I am trying to make a console program to automate some tasks that I couldn't quite do with a BAT file. I want to call "signcode.exe" from the Windows SDK, the bin folder with all the tools in my system PATH, and I can call "signcode" from anywhere, but Process.Start is ignoring the path.

Current code:

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

I've confirmed that StartInfo.EnvironmentVariables["Path"] matches my system path, and contains the Windows SDK folder. Setting it manually doesn't work either.

I've even tried setting TempPath as shown on the MSDN page for EnvironmentVariables Property, but that didn't work either. I wonder why you would be able to set this if it has no effect.

If System.Diagnostics.Process cannot use the path, are there any other functions I could use? I'd like to see the output of the command in my console application as well.

Here is some additional debug values:

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'

The path "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin" is where signtool.exe is, and I can run it from a command prompt by simply typing signtool, but if I run this application from the same prompt, it doesn't register that path.


回答1:


I'm pretty sure Process.Start does respect PATH.

  • Are you sure your signCommand value is correct?
  • Is the directory value in PATH specified using quotes? The docs mention that such values will not be respected.

Note that FileName can also be a full path to the executable.




回答2:


Adding to mhutch's answer: It does indeed take PATH into consideration, but I have noticed you actually need to restart Visual Studio to pick up any path changes. It is kind of sneaky.




回答3:


Well, I guess the problem was related to what mhutch said, from the MSDN docs:

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.

I saw that initially, but it seemed strange so I disregard it. Not sure why that's the case but it seems to be.

I tried copying signtool.exe to C:\sign\tool\bin and added that to my path, and then my code worked, so I guess because I have quotes in that path due to the spaces, I am SOL and will have to manually search the path for the windows SDK path unless there is some way to add something with spaces to the path without using quotes.




回答4:


If you updated PATH recently, be sure to restart Visual Studio. Environment variables are loaded at the launch of Visual Studio. Note that this applies to DEBUG mode execution.




回答5:


I believe you're looking for the ProcessStartInfo.WorkingDirectory property.




回答6:


The StartInfo filename is actually the full path to the executable

For example, on a wrapper I have for x264, it looks like this:

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

I'd sense-check the code by adding a try {}, catch {} in there and writing the actual filename you are trying to call into the debug if you have an error.

Otherwise add something like the below:

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

EDIT: Added a full example - this searches for CCleaner and then runs it with the "/AUTO" switch. Just tested and works fine.

        // 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);



回答7:


Your code does seem to take the path into account for me.

It's hard to say what might be wrong in your case, but you might try running your command through cmd.exe:

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


来源:https://stackoverflow.com/questions/8003272/can-process-start-take-the-system-path-into-account

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!