¿Cómo obtener la ruta completa del proceso en ejecución?


112

Tengo una aplicación que está cambiando algunas configuraciones de otra aplicación (es una aplicación C # simple que se ejecuta haciendo doble clic (no se requiere configuración)).

Después de cambiar la configuración, necesito reiniciar la otra aplicación para que refleje la configuración modificada.

Entonces, para hacerlo, tengo que matar el proceso en ejecución y comenzar el proceso de nuevo, pero el problema es que después de matar no puedo encontrar el proceso. (La razón es que el sistema no sabe dónde está el archivo exe ..)

¿Hay alguna forma de averiguar la ruta del proceso en ejecución o exe, si se está ejecutando?

No quiero dar la ruta manualmente, es decir, si se está ejecutando, obtenga la ruta, elimine el proceso y comience de nuevo ... lo manejaré más tarde

Respuestas:


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.

Hay un problema con esta API, si está ejecutando este código en una aplicación de 32 bits, no podrá acceder a las rutas de las aplicaciones de 64 bits, por lo que tendrá que compilar y ejecutar su aplicación como una aplicación de 64 bits ( Propiedades del proyecto → Construir → Plataforma objetivo → x64).


11
@GAPS: Estoy seguro de que quiere decir "obtenga su instancia de proceso como quiera que la obtenga aquí".
Jeff Mercado

4
Da problema Acceso denegado en línea ¿ string fullPath = process.Modules[0].FileName;Alguna idea por favor?
Sami

7
En lugar de cambiar Platform Target a x64, cambié Platform Target a Cualquiera y desmarqué la opción Preferir 32 bits
Prat

13
Según mis medidas, llamar process.Modules[0]es 50 veces más lento que llamar process.MainModule.
Luca Cremonesi

1
¿Existe alguna garantía de que el primer módulo sea el módulo principal?
Sam

112

Lo que puede hacer es usar WMI para obtener las rutas. Esto le permitirá obtener la ruta independientemente de que sea una aplicación de 32 o 64 bits. Aquí hay un ejemplo que demuestra cómo puede obtenerlo:

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

Tenga en cuenta que tendrá que hacer referencia al System.Management.dllensamblado y usar el System.Managementespacio de nombres.

Para obtener más información sobre qué otra información puede obtener de estos procesos, como la línea de comando utilizada para iniciar el programa ( CommandLine), consulte la clase Win32_Process y WMI .NET para obtener más información.


1
tu respuesta es increíble, pero mi aplicación actual es pequeña ... tengo esto en cuenta
PawanS

3
+1 quizás para esta pregunta es una exageración, pero debido a la independencia de 32/64 bits, este método fue muy útil cuando quería obtener información de proceso de 64 bits de un proceso de 32 bits en ejecución .
Mike Fuchs

1
A diferencia de la Respuesta aceptada, esto también funciona en entornos de Terminal Server. Buen trabajo, me ayudó mucho!
MC

1
Tenga en cuenta que la Pathpropiedad establecida desde mo["ExecutablePath"]es nullpara algunos procesos.
Sam

2
En caso de que Visual Studio se queje de que faltan referencias para Process.GetProcesses()y results.Cast<>también necesita agregar una using System.Linqdirectiva.
kibitzerCZ

26

Supongo que ya tiene el objeto de proceso del proceso en ejecución (por ejemplo, por GetProcessesByName ()). Luego puede obtener el nombre del archivo ejecutable usando

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

2
si no usa: var p = Process.GetCurrentProcess (); string filename = p.MainModule.FileName;
Andreas

3
El "Un proceso de 32 bits no puede acceder a módulos de un proceso de 64 bits". Lamentablemente, la limitación también está aquí.
Roland Pihlakas

18

Una solución para:

  • Procesos de 32 bits y de 64 bits
  • System.Diagnostics solamente (sin System.Diagnostics )

Usé la solución de Russell Gantman y la reescribí como un método de extensión que puede usar así:

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

Con esta implementación:

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 devuelve BOOL. No necesitamos compararlo con 0. pinvoke.net/default.aspx/kernel32.QueryFullProcessImageName
vik_78

8

Al combinar las respuestas de Sanjeevakumar Hiremath y Jeff Mercado, de alguna manera puede solucionar el problema al recuperar el ícono de un proceso de 64 bits en un proceso de 32 bits.

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

Esto puede ser un poco lento y no funciona en todos los procesos que carecen de un icono "válido".


Este uso podría mejorarse ligeramente con string query = "SELECT ExecutablePath, ProcessID FROM Win32_Process WHERE ProcessID = " + process.Id;... pero este método sigue siendo bastante lento, obtener todos los resultados y 'almacenarlos en caché' sería la mejor mejora de velocidad, si está obteniendo la ruta de más de 1 proceso
Thymine

8

Esta es una solución confiable que funciona con aplicaciones de 32 y 64 bits .

Agregue estas referencias:

utilizando System.Diagnostics;

utilizando System.Management;

Agregue este método a su proyecto:

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

Ahora úsalo así:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Tenga en cuenta que si conoce la identificación del proceso, este método devolverá el ExecutePath correspondiente.

Extra, para los interesados:

Process.GetProcesses() 

... le dará una serie de todos los procesos que se están ejecutando actualmente, y ...

Process.GetCurrentProcess()

... le dará el proceso actual, junto con su información, por ejemplo, Id, etc. y también un control limitado, por ejemplo, Kill, etc. *


4

Puede utilizar pInvoke y una llamada nativa como la siguiente. Esto no parece tener la limitación de 32/64 bits (al menos en mis pruebas)

Aqui esta el codigo

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

Tratar:

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: esto es para Ejecutar Asamblea (que se está ejecutando actualmente)
Sonal Satpute

¡Guauu! ¡Gracias! La mejor solución de todos los tiempos, porque funciona incluso en 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

Para otros, si desea encontrar otro proceso del mismo ejecutable, puede usar:

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

Llegué a este hilo mientras buscaba el directorio actual de un proceso en ejecución. En .net 1.1, Microsoft introdujo:

Directory.GetCurrentDirectory();

Parece funcionar bien (pero no devuelve el nombre del proceso en sí).


Eso solo devolverá el directorio en el que se encuentra el ejecutable en algunas circunstancias. Puede, por ejemplo, abrir una línea de comando, cambiar a cualquier directorio aleatorio y ejecutar el ejecutable especificando una ruta completa; GetCurrentDirectory () devolverá el directorio desde el que ejecutó en lugar del directorio del ejecutable. Desde el enlace : "El directorio actual es distinto del directorio original, que es desde donde se inició el proceso".
Dave Ruske
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.