Process.Start() 可以考虑系统路径吗?

发布于 2024-12-13 17:44:06 字数 2966 浏览 3 评论 0原文

我已经对此进行了一段时间的搜索和实验,但我没有运气。

我正在尝试制作一个控制台程序来自动执行一些我无法使用 BAT 文件完成的任务。我想从 Windows SDK 调用“signcode.exe”,该 bin 文件夹包含系统路径中的所有工具,并且我可以从任何地方调用“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 属性,但这也不起作用。我想知道如果没有效果,为什么你可以设置这个。

如果 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 即可打开命令提示符,但如果我从同一提示符运行此应用程序,它不会注册该路径。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

等数载,海棠开 2024-12-20 17:44:06

添加 mhutch 的答案:它确实考虑了 PATH,但我注意到您实际上需要重新启动 Visual Studio 才能获取任何路径更改。这有点鬼鬼祟祟的。

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.

二智少女 2024-12-20 17:44:06

我很确定 Process.Start 确实尊重 PATH。

  • 您确定您的signCommand值正确吗?
  • PATH 中的目录值是否使用引号指定? 文档提到此类值不会受到尊重。

请注意,FileName 也可以是可执行文件的完整路径。

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.

惟欲睡 2024-12-20 17:44:06

如果您最近更新了 PATH,请务必重新启动 Visual Studio。环境变量在 Visual Studio 启动时加载。请注意,这适用于 DEBUG 模式执行。

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.

陌伤ぢ 2024-12-20 17:44:06

好吧,我猜这个问题与 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 路径的路径,除非有某种方法可以在不使用引号的情况下向路径添加带有空格的内容。

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.

我是有多爱你 2024-12-20 17:44:06

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");
    }

编辑:添加了一个完整的示例 - 这会搜索 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);

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);
壹場煙雨 2024-12-20 17:44:06

您的代码似乎确实考虑了我的路径。

很难说您的情况可能出了什么问题,但您可以尝试通过 cmd.exe 运行命令:

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

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 ...";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文