【问题标题】:How to get the full path of running process?如何获取运行进程的完整路径?
【发布时间】:2011-03-31 08:23:52
【问题描述】:

我有一个应用程序正在更改另一个应用程序的某些设置(它是一个简单的 C# 应用程序,通过双击运行(无需设置)。

更改设置后,我需要重新启动其他应用程序以反映更改的设置。

因此,我必须杀死正在运行的进程并重新启动该进程,但问题是杀死后我无法找到该进程。 (原因是系统不知道exe文件在哪里..)

如果正在运行,有什么方法可以找出运行进程或exe的路径?

我不想手动提供路径,即如果它正在运行获取路径,则终止进程并重新启动......我稍后会处理

【问题讨论】:

    标签: c#


    【解决方案1】:
     using System.Diagnostics;
     var process = Process.GetCurrentProcess(); // Or whatever method you are using
     string fullPath = process.MainModule.FileName;
     //fullPath has the path to exe.
    

    此 API 有一个问题,如果您在 32 位应用程序中运行此代码,您将无法访问 64 位应用程序路径,因此您必须将您的应用程序编译并运行为 64-位应用程序(项目属性→构建→平台目标→x64)。

    【讨论】:

    • @GAPS:我敢肯定他的意思是,“获取你的流程实例,但你在这里得到它。”
    • 它给出了问题访问被拒绝在线string fullPath = process.Modules[0].FileName;任何想法吗?
    • 我没有将 Platform Target 更改为 x64,而是将 Platform Target 更改为 Any 并取消选中 Prefer 32 bit 选项
    • 根据我的测量,调用 process.Modules[0] 比调用 process.MainModule50 倍
    • 能保证第一个模块是主模块吗?
    【解决方案2】:

    您可以做的是使用 WMI 来获取路径。无论它是 32 位还是 64 位应用程序,这都将允许您获取路径。这是一个演示如何获取它的示例:

    // include the namespace
    using System.Management;
    
    var wmiQueryString = "SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process";
    using (var searcher = new ManagementObjectSearcher(wmiQueryString))
    using (var results = searcher.Get())
    {
        var query = from p in Process.GetProcesses()
                    join mo in results.Cast<ManagementObject>()
                    on p.Id equals (int)(uint)mo["ProcessId"]
                    select new
                    {
                        Process = p,
                        Path = (string)mo["ExecutablePath"],
                        CommandLine = (string)mo["CommandLine"],
                    };
        foreach (var item in query)
        {
            // Do what you want with the Process, Path, and CommandLine
        }
    }
    

    请注意,您必须引用 System.Management.dll 程序集并使用 System.Management 命名空间。

    有关您可以从这些进程中获取哪些其他信息的更多信息,例如用于启动程序的命令行 (CommandLine),请参阅 Win32_Process 类和 WMI .NET 了解更多信息。

    【讨论】:

    • 您的回答很棒,但我当前的应用程序很小......我记住了这一点
    • +1 也许对于这个问题来说这有点过头了,但是由于 32/64 位的独立性,当我想得到 64bit-process information from a running 32bit process 时,这种方法非常方便。
    • 与公认的答案不同,这也适用于终端服务器环境。干得好,对我帮助很大!
    • 请注意,对于某些进程,从mo["ExecutablePath"] 设置的Path 属性是null
    • 如果 Visual Studio 抱怨缺少对 Process.GetProcesses()results.Cast&lt;&gt; 的引用,您还需要添加 using System.Linq 指令。
    【解决方案3】:

    解决方案:

    • 32 位和 64 位进程
    • 仅 System.Diagnostics (无 System.Management)

    我使用了solution from Russell Gantman 并将其重写为您可以这样使用的扩展方法:

    var process = Process.GetProcessesByName("explorer").First();
    string path = process.GetMainModuleFileName();
    // C:\Windows\explorer.exe
    

    有了这个实现:

    internal static class Extensions {
        [DllImport("Kernel32.dll")]
        private static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] uint dwFlags, [Out] StringBuilder lpExeName, [In, Out] ref uint lpdwSize);
    
        public static string GetMainModuleFileName(this Process process, int buffer = 1024) {
            var fileNameBuilder = new StringBuilder(buffer);
            uint bufferLength = (uint)fileNameBuilder.Capacity + 1;
            return QueryFullProcessImageName(process.Handle, 0, fileNameBuilder, ref bufferLength) ?
                fileNameBuilder.ToString() :
                null;
        }
    }
    

    【讨论】:

    【解决方案4】:

    我猜你已经有了正在运行的进程的进程对象(例如GetProcessesByName())。
    然后,您可以使用以下命令获取可执行文件名:

    Process p;
    string filename = p.MainModule.FileName;
    

    【讨论】:

    • 如果不使用: var p = Process.GetCurrentProcess();字符串文件名 = p.MainModule.FileName;
    • “32 位进程无法访问 64 位进程的模块。”不幸的是,限制也在这里。
    【解决方案5】:

    通过结合 Sanjeevakumar Hiremath 和 Jeff Mercado 的答案,您实际上可以在某种程度上解决在 32 位进程中从 64 位进程中检索图标时的问题。

    using System;
    using System.Management;
    using System.Diagnostics;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                int processID = 6680;   // Change for the process you would like to use
                Process process = Process.GetProcessById(processID);
                string path = ProcessExecutablePath(process);
            }
    
            static private string ProcessExecutablePath(Process process)
            {
                try
                {
                    return process.MainModule.FileName;
                }
                catch
                {
                    string query = "SELECT ExecutablePath, ProcessID FROM Win32_Process";
                    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
    
                    foreach (ManagementObject item in searcher.Get())
                    {
                        object id = item["ProcessID"];
                        object path = item["ExecutablePath"];
    
                        if (path != null && id.ToString() == process.Id.ToString())
                        {
                            return path.ToString();
                        }
                    }
                }
    
                return "";
            }
        }
    }
    

    这可能有点慢,并且不适用于缺少“有效”图标的每个进程。

    【讨论】:

    • 使用string query = "SELECT ExecutablePath, ProcessID FROM Win32_Process WHERE ProcessID = " + process.Id; 可能会稍微改进这种用法...但是这种方法仍然很慢,如果你得到所有结果并“缓存”它们将是最好的速度改进多个进程的路径
    【解决方案6】:

    这是一个可靠的解决方案,适用于 32 位64 位 应用程序。

    添加这些引用:

    使用 System.Diagnostics;

    使用 System.Management;

    将此方法添加到您的项目中:

    public static string GetProcessPath(int processId)
    {
        string MethodResult = "";
        try
        {
            string Query = "SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = " + processId;
    
            using (ManagementObjectSearcher mos = new ManagementObjectSearcher(Query))
            {
                using (ManagementObjectCollection moc = mos.Get())
                {
                    string ExecutablePath = (from mo in moc.Cast<ManagementObject>() select mo["ExecutablePath"]).First().ToString();
    
                    MethodResult = ExecutablePath;
    
                }
    
            }
    
        }
        catch //(Exception ex)
        {
            //ex.HandleException();
        }
        return MethodResult;
    }
    

    现在像这样使用它:

    int RootProcessId = Process.GetCurrentProcess().Id;
    
    GetProcessPath(RootProcessId);
    

    注意,如果你知道进程的id,那么这个方法会返回对应的ExecutePath。

    额外的,对于那些感兴趣的人:

    Process.GetProcesses() 
    

    ...将为您提供所有当前正在运行的进程的数组,并且...

    Process.GetCurrentProcess()
    

    ...将为您提供当前流程以及他们的信息,例如Id 等以及有限的控制,例如杀戮等*

    【讨论】:

      【解决方案7】:

      您可以使用 pInvoke 和本机调用,如下所示。这似乎没有 32 / 64 位限制(至少在我的测试中)

      这里是代码

      using System.Runtime.InteropServices;
      
          [DllImport("Kernel32.dll")]
          static extern uint QueryFullProcessImageName(IntPtr hProcess, uint flags, StringBuilder text, out uint size);
      
          //Get the path to a process
          //proc = the process desired
          private string GetPathToApp (Process proc)
          {
              string pathToExe = string.Empty;
      
              if (null != proc)
              {
                  uint nChars = 256;
                  StringBuilder Buff = new StringBuilder((int)nChars);
      
                  uint success = QueryFullProcessImageName(proc.Handle, 0, Buff, out nChars);
      
                  if (0 != success)
                  {
                      pathToExe = Buff.ToString();
                  }
                  else
                  {
                      int error = Marshal.GetLastWin32Error();
                      pathToExe = ("Error = " + error + " when calling GetProcessImageFileName");
                  }
              }
      
              return pathToExe;
          }
      

      【讨论】:

        【解决方案8】:
        private void Test_Click(object sender, System.EventArgs e){
           string path;
           path = System.IO.Path.GetDirectoryName( 
              System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase );
            Console.WriiteLine( path );  
        }
        

        【讨论】:

        • @GAPS:这是用于执行程序集(当前正在运行)
        • 哇!谢谢!有史以来最好的解决方案,因为它甚至可以在 FreeBSD 上运行。
        【解决方案9】:

        试试:

        using System.Diagnostics;
        
        ProcessModuleCollection modules = Process.GetCurrentProcess().Modules;
        string processpathfilename;
        string processmodulename;
        if (modules.Count > 0) {
            processpathfilename = modules[0].FileName;
            processmodulename= modules[0].ModuleName;
        } else {
            throw new ExecutionEngineException("Something critical occurred with the running process.");
        }
        

        【讨论】:

          【解决方案10】:
          using System;
          using System.Diagnostics;
          
          class Program
          {
              public static void printAllprocesses()
              {
                  Process[] processlist = Process.GetProcesses();
          
                  foreach (Process process in processlist)
                  {
                      try
                      {
                          String fileName = process.MainModule.FileName;
                          String processName = process.ProcessName;
          
                          Console.WriteLine("processName : {0},  fileName : {1}", processName, fileName);
                      }catch(Exception e)
                      {
                          /* You will get access denied exception for system processes, We are skiping the system processes here */
                      }
          
                  }
              }
          
              static void Main()
              {
                  printAllprocesses();
              }
          
          }
          

          【讨论】:

            【解决方案11】:

            对于其他人,如果你想找到同一个可执行文件的另一个进程,你可以使用:

            public bool tryFindAnotherInstance(out Process process) {
                Process thisProcess = Process.GetCurrentProcess();
                string thisFilename = thisProcess.MainModule.FileName;
                int thisPId = thisProcess.Id;
                foreach (Process p in Process.GetProcesses())
                {
                    try
                    {
                        if (p.MainModule.FileName == thisFilename && thisPId != p.Id)
                        {
                            process = p;
                            return true;
                        }
                    }
                    catch (Exception)
                    {
            
                    }
                }
                process = default;
                return false;
            }
            

            【讨论】:

              【解决方案12】:

              Process 类有一个成员 StartInfo,您应该检查一下:

              【讨论】:

              • 这仅适用于使用Process.Start() 启动的本地进程,不适用于现有进程。
              • 没错。与其说是“这个过程是如何开始的”,不如说是“如何开始这个过程”。
              【解决方案13】:

              我在寻找执行进程的当前目录时进入了这个线程。微软在 .net 1.1 中引入:

              Directory.GetCurrentDirectory();
              

              似乎运行良好(但不返回进程本身的名称)。

              【讨论】:

              • 这只会在某些情况下返回可执行文件所在的目录。例如,您可以打开命令行,切换到任何随机目录,然后通过指定完整路径来运行可执行文件; GetCurrentDirectory() 将返回您执行的目录,而不是可执行文件的目录。来自link“当前目录与原始目录不同,原始目录是启动进程的目录。”
              猜你喜欢
              • 1970-01-01
              • 2013-01-26
              • 1970-01-01
              • 2012-02-18
              • 1970-01-01
              • 1970-01-01
              • 2012-05-16
              • 2011-09-19
              • 1970-01-01
              相关资源
              最近更新 更多