如何获得运行过程的完整路径?


112

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

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

这样做,我必须终止正在运行的进程并重新启动该进程,但是问题是在终止后我找不到该进程。(原因是系统不知道exe文件在哪里。)

有什么办法找出正在运行的进程或exe的路径(如果正在运行)?

我不想手动给定路径,即如果它正在运行,请获取路径,终止该过程,然后再重新开始....我稍后会处理

Answers:


157
 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)。


11
@GAPS:我确信他的意思是,“无论您在何处获取流程实例,都可以。”
杰夫·梅卡多

4
它给出了问题在线访问被拒绝,string fullPath = process.Modules[0].FileName;请问任何想法?
萨米(Sami)2013年

7
相反,改变目标平台到x64的,我改变了目标平台以任何并且未选中身高32位的选项
普拉特

13
根据我的测试,通话process.Modules[0]慢50倍比调用process.MainModule
卡·克雷莫内西

1
是否可以保证第一个模块是主模块?
山姆

112

您可以做的是使用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
您的回答很棒,但我当前的应用程序很小...我谨记这一点
PawanS 2011年

3
+1对于这个问题可能是一个过大的问题,但是由于32/64位的独立性,当我想从运行的32位进程中获取64位进程信息时,此方法非常方便。
Mike Fuchs 2012年

1
与已接受的答案不同,这也适用于终端服务器环境。干得好,对我帮助很大!
MC

1
注意,Path财产设定mo["ExecutablePath"]null对于某些工艺。
2014年

2
如果Visual Studio中抱怨缺少引用Process.GetProcesses()results.Cast<>您还需要添加using System.Linq指令。
kibitzerCZ

26

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

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

2
如果不使用:var p = Process.GetCurrentProcess(); 字符串文件名= p.MainModule.FileName;
安德烈亚斯(Andreas)2012年

3
“ 32位进程无法访问64位进程的模块。” 不幸的是,这里也有局限性。
罗兰·皮拉卡斯

18

解决方案:

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

我使用了拉塞尔·甘特曼(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;
    }
}

1
QueryFullProcessImageName返回BOOL。我们不需要将其与0进行比较。pinvoke.net
default.aspx/

8

通过结合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;但是此方法仍然相当慢,如果您要使用多个过程,那么获取所有结果并“缓存”它们将是最好的速度改进
Thymine

8

这是可与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等)以及有限的控制权(例如Kill等)*


4

您可以使用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;
    }

1

尝试:

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

0
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:这是用于执行程序集(当前正在运行)
Sonal Satpute

哇!谢谢!有史以来最好的解决方案,因为即使在FreeBSD上也可以使用。
BIV

0
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();
    }

}

0

对于其他用户,如果要查找同一可执行文件的另一个进程,则可以使用:

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


-3

我在寻找执行进程的当前目录时进入了该线程。在.net 1.1中,Microsoft引入了:

Directory.GetCurrentDirectory();

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


在某些情况下,这只会返回可执行文件所在的目录。例如,您可以打开命令行,更改为任意随机目录,然后通过指定可执行文件的完整路径来运行该可执行文件。GetCurrentDirectory()将返回您从中执行的目录,而不是可执行文件的目录。From 链接“当前目录与原始目录不同,原始目录是从该目录开始的。”
Dave Ruske 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.