【问题标题】:Can Process.Start() take the system PATH into account?Process.Start() 可以考虑系统路径吗?
【发布时间】:2011-12-21 15:24:55
【问题描述】:

我一直在搜索和试验这个,但我没有运气。

我正在尝试制作一个控制台程序来自动执行一些我无法使用 BAT 文件完成的任务。我想从 Windows SDK(包含系统 PATH 中所有工具的 bin 文件夹)调用“signcode.exe”,并且可以从任何地方调用“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 文件夹。手动设置也不行。

我什至尝试过在 MSDN 页面上为 EnvironmentVariables Property 设置 TempPath,但这也不起作用。我想知道如果它没有效果,为什么你可以设置它。

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

【问题讨论】:

  • “不起作用”没有错误。你得到什么例外?至于你问题的输出部分,看StandardOutput
  • sign.Start()后面注释的异常和它抛出的消息,是Win32Exception。
  • 你说得对,我没有阅读代码块。 Win32Exception 不是来自签名工具本身吗?找不到您要签名的文件?尝试使用 /h 或其他不需要文件的参数来启动它。
  • @CodeCaster 不用担心,我应该在问题中说得更清楚,我会试一试,看看我得到了什么,谢谢!
  • 我试过“signtool.exe 签名/?”但仍然得到异常而不是帮助内容输出到 STDOUT。

标签: c# path system.diagnostics process.start


【解决方案1】:

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

【讨论】:

  • 哇,你为我节省了 1 小时(或更长时间)来寻找这个...... :)
  • 用了几个小时试图解决这个问题,直到我偶然发现了这个解决方案。哇:)
【解决方案2】:

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

  • 您确定您的 signCommand 值正确吗?
  • PATH 中的目录值是否使用引号指定? The docs 提及此类价值观将不被尊重。

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

【讨论】:

  • 我想避免使用可执行文件的完整路径,因为它可能位于不同的位置。我的路径确实引用了它,因为它在C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin 中。我认为它必须被引用,因为路径中有空格,我还从文档中注意到,如果 PATH 包含引号,则会抛出 FileNotFoundException,但我得到的是 Win32Exception
  • 我没有看到任何提到 FileNotFoundException...如果找不到可执行文件,它总是会抛出 Win32Exception。奇怪的是 Process.Start 的文档确实提到了使用 PATH 值,但 Win32 CreateProcess 文档明确表示不使用搜索路径,所以我猜 Process.Start 在传递之前使用 PATH 解析全名CreateProcess 的值,它可能在解析/拆分 PATH 的方式上受到限制。
  • 您总是可以手动搜索 PATH:string ResolveFullPath (string name) { return fullName = Path.IsPathRooted(name)?名称:Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator).Select(dir => Path.Combine(dir.Trim('"'), name)).First(File.Exists); }跨度>
  • 我在 windows 的命令行中使用 maven 被抓到了 - 它在路径中,但仅使用 'mvn' 不起作用,因为它是一个批处理文件 - 而您需要使用 'mvn.蝙蝠'
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      我相信您正在寻找ProcessStartInfo.WorkingDirectory property

      【讨论】:

      • 我不想更改工作目录,因为我将从某个文件夹运行此应用程序并参考与此路径相关的文件,并希望它成为工作目录,但我更喜欢不必指定 signtool.exe 的完整路径。
      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-09-22
          • 2021-08-26
          • 2013-10-19
          • 1970-01-01
          • 2015-02-12
          • 2018-04-19
          • 1970-01-01
          相关资源
          最近更新 更多