Comment obtenir le chemin complet du processus en cours?


112

J'ai une application qui modifie certains paramètres d'une autre application (c'est une simple application C # qui s'exécute en double-cliquant (aucune configuration requise)).

Après avoir modifié les paramètres, je dois redémarrer l'autre application afin qu'elle reflète les paramètres modifiés.

Donc, pour ce faire, je dois tuer le processus en cours et recommencer le processus, mais le problème est qu'après avoir tué, je ne parviens pas à trouver le processus. (La raison est que le système ne sait pas où se trouve le fichier exe.)

Existe-t-il un moyen de trouver le chemin du processus en cours d'exécution ou de l'exe, s'il est en cours d'exécution?

Je ne veux pas donner le chemin manuellement, c'est-à-dire que s'il est en cours d'exécution, récupérez le chemin, tuez le processus et recommencez sinon .... Je traiterai plus tard

Réponses:


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.

Il y a un problème avec cette API, si vous exécutez ce code dans une application 32 bits, vous ne pourrez pas accéder aux chemins d'application 64 bits, vous devrez donc compiler et exécuter votre application en tant qu'application 64 bits ( Propriétés du projet → Construire → Cible de la plateforme → x64).


11
@GAPS: Je suis sûr qu'il veut dire, "obtenez votre instance de processus comme vous l'avez ici."
Jeff Mercado

4
Cela pose problème. L'accès est refusé en ligne. string fullPath = process.Modules[0].FileName;Une idée s'il vous plaît?
Sami

7
Au lieu de changer Platform Target en x64, j'ai changé Platform Target en Any et décoché l' option Préférer 32 bits
Prat

13
D'après mes mesures, appeler process.Modules[0]est 50 fois plus lent que d'appeler process.MainModule.
Luca Cremonesi

1
Y a-t-il une garantie que le premier module est le module principal?
Sam

112

Ce que vous pouvez faire, c'est utiliser WMI pour obtenir les chemins. Cela vous permettra d'obtenir le chemin, qu'il s'agisse d'une application 32 bits ou 64 bits. Voici un exemple montrant comment vous pouvez l'obtenir:

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

Notez que vous devrez référencer l' System.Management.dllassembly et utiliser l' System.Managementespace de noms.

Pour plus d'informations sur les autres informations que vous pouvez extraire de ces processus, telles que la ligne de commande utilisée pour démarrer le programme ( CommandLine), consultez la classe Win32_Process et WMI .NET pour plus d'informations.


1
votre réponse est géniale, mais mon application actuelle est petite ... Je garde cela à l'esprit
PawanS

3
+1 peut-être pour cette question, c'est exagéré, mais en raison de l'indépendance 32/64 bits, cette méthode s'est avérée très pratique lorsque je voulais obtenir des informations de processus 64 bits à partir d'un processus 32 bits en cours d'exécution .
Mike Fuchs

1
Contrairement à la réponse acceptée, cela fonctionne également dans les environnements Terminal Server. Bon travail, m'a beaucoup aidé!
MC

1
Notez que la Pathpropriété définie à partir de mo["ExecutablePath"]est nullpour certains processus.
Sam

2
Dans le cas où Visual Studio se plaint de références manquantes pour Process.GetProcesses()et results.Cast<>vous devez également ajouter une using System.Linqdirective.
kibitzerCZ

26

Je suppose que vous avez déjà l'objet de processus du processus en cours (par exemple par GetProcessesByName ()). Vous pouvez ensuite obtenir le nom du fichier exécutable en utilisant

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

2
sinon utiliser: var p = Process.GetCurrentProcess (); string filename = p.MainModule.FileName;
Andreas

3
"Un processus 32 bits ne peut pas accéder aux modules d'un processus 64 bits." la limitation est malheureusement là aussi.
Roland Pihlakas

18

Une solution pour:

  • Processus 32 bits ET 64 bits
  • System.Diagnostics uniquement (pas de System.Management)

J'ai utilisé la solution de Russell Gantman et l' ai réécrite comme une méthode d'extension que vous pouvez utiliser comme ceci:

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

Avec cette implémentation:

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 renvoie BOOL. Nous n'avons pas besoin de le comparer avec 0. pinvoke.net/default.aspx/kernel32.QueryFullProcessImageName
vik_78

8

En combinant les réponses de Sanjeevakumar Hiremath et de Jeff Mercado, vous pouvez en fait contourner le problème lors de la récupération de l'icône à partir d'un processus 64 bits dans un processus 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 "";
        }
    }
}

Cela peut être un peu lent et ne fonctionne pas sur tous les processus qui n'ont pas d'icône «valide».


Cette utilisation pourrait être légèrement améliorée avec string query = "SELECT ExecutablePath, ProcessID FROM Win32_Process WHERE ProcessID = " + process.Id;... mais cette méthode est encore assez lente, obtenir tous les résultats et les `` mettre en cache '' serait la meilleure amélioration de la vitesse, si vous obtenez le chemin de plus d'un processus
Thymine

8

Voici une solution fiable qui fonctionne à la fois avec 32 bits applications bits et 64 bits .

Ajoutez ces références:

en utilisant System.Diagnostics;

en utilisant System.Management;

Ajoutez cette méthode à votre projet:

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

Maintenant, utilisez-le comme ceci:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Notez que si vous connaissez l'id du processus, cette méthode renverra l'ExecutePath correspondant.

Extra, pour ceux qui sont intéressés:

Process.GetProcesses() 

... vous donnera un tableau de tous les processus en cours d'exécution, et ...

Process.GetCurrentProcess()

... vous donnera le processus actuel, ainsi que leurs informations, par exemple Id, etc. et également un contrôle limité, par exemple Kill, etc. *


4

Vous pouvez utiliser pInvoke et un appel natif tel que le suivant. Cela ne semble pas avoir la limitation 32/64 bits (du moins dans mes tests)

Voici le code

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

Essayer:

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: c'est pour Executing Assembly (qui est actuellement en cours d'exécution)
Sonal Satpute

Hou la la! Merci! La meilleure solution de tous les temps, car fonctionne même sur 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

Pour les autres, si vous souhaitez trouver un autre processus du même exécutable, vous pouvez utiliser:

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

Je suis arrivé à ce fil en recherchant le répertoire actuel d'un processus en cours d'exécution. Dans .net 1.1, Microsoft a introduit:

Directory.GetCurrentDirectory();

Semble bien fonctionner (mais ne renvoie pas le nom du processus lui-même).


Cela ne renverra que le répertoire dans lequel se trouve l'exécutable dans certaines circonstances. Vous pouvez, par exemple, ouvrir une ligne de commande, passer à n'importe quel répertoire aléatoire et exécuter l'exécutable en lui spécifiant un chemin complet; GetCurrentDirectory () retournera le répertoire à partir duquel vous avez exécuté plutôt que le répertoire de l'exécutable. From link : "Le répertoire actuel est distinct du répertoire d'origine, qui est celui à partir duquel le processus a été lancé."
Dave Ruske
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.