129

I am having an application that is changing some settings of another application (it is a simple C# application that run by double clicking (no setup required)).

After changing the settings I need to restart the other application so that it reflects the changed settings.

So to do, I have to kill the running process and start the process again, But the problem is after killing I am not able to find the process. (Reason is system do not know where the exe file is..)

Is there any way to find out the path of running process or exe, if it is running?

I do not want to give path manually, i.e. if it is running get the path, kill the process and start again else .... I will handle later

Yennefer
  • 5,704
  • 7
  • 31
  • 44
PawanS
  • 7,033
  • 14
  • 43
  • 71

17 Answers17

199
 using System.Diagnostics;
 var process = Process.GetCurrentProcess(); // Or whatever method you are using
 string fullPath = process.MainModule.FileName;
 //fullPath has the path to exe.

There is one catch with this API, if you are running this code in 32 bit application, you'll not be able to access 64-bit application paths, so you'd have to compile and run you app as 64-bit application (Project Properties → Build → Platform Target → x64).

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Sanjeevakumar Hiremath
  • 10,985
  • 3
  • 41
  • 46
116

What you can do is use WMI to get the paths. This will allow you to get the path regardless it's a 32-bit or 64-bit application. Here's an example demonstrating how you can get it:

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

Note that you'll have to reference the System.Management.dll assembly and use the System.Management namespace.

For more info on what other information you can grab out of these processes such as the command line used to start the program (CommandLine), see the Win32_Process class and WMI .NET for for more information.

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • 1
    your answer is awesome, but my current app is small one... I keep this in mind – PawanS Mar 31 '11 at 09:12
  • 3
    +1 perhaps for this question it's an overkill, but because of the 32/64bit independency, this method came in really handy when I wanted to get [64bit-process information from a running 32bit process](http://stackoverflow.com/questions/9501771/how-to-avoid-a-win32-exception-when-accessing-process-mainmodule-filename-in-c). – Mike Fuchs Mar 16 '12 at 13:33
  • 1
    Unlike the accepted Answer, this also works in Terminal Server Enviroments. Good job, helped me much! – M C Feb 20 '14 at 10:41
  • 1
    Note that the `Path` property set from `mo["ExecutablePath"]` is `null` for some processes. – Sam Dec 08 '14 at 04:01
  • @Sam do you know why it is null? Trying the method above gives me 52 processes with not null, but `Process.GetProcesses().Length` is equal to 112. – andreas Jan 01 '15 at 16:49
  • @andreas, no; I don't know exactly why. It seems to be normal in Windows. Even if you open up Task Manager in Windows and look over the processes, you should see that only some of them have corresponding executables shown. – Sam Jan 02 '15 at 22:11
  • This solution seems to just filter out the non-Win32 processes in the GetProcesses() results. Yet, there does not appear to be an easy way to determine this important characteristic from the Process component itself. How frustrating. The use cases for this component (façade) must have been pretty narrow. – George Sep 28 '15 at 18:31
  • 3
    In case Visual Studio complains about missing references for `Process.GetProcesses()` and `results.Cast<>` you also need to add `using System.Linq` directive. – kibitzerCZ Jan 27 '17 at 08:59
26

A solution for:

  • Both 32-bit AND 64-bit processes
  • System.Diagnostics only (no System.Management)

I used the solution from Russell Gantman and rewritten it as an extension method you can use like this:

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

With this implementation:

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;
    }
}
Bruno Zell
  • 7,761
  • 5
  • 38
  • 46
  • 1
    QueryFullProcessImageName returns BOOL. We don't need to compare it with 0. https://www.pinvoke.net/default.aspx/kernel32.QueryFullProcessImageName – vik_78 Aug 30 '18 at 12:42
  • 2
    There is a permison problem: `System.ComponentModel.Win32Exception: 'Access is denied'`. – heLomaN Nov 24 '21 at 14:30
25

I guess you already have the process object of the running process (e.g. by GetProcessesByName()).
You can then get the executable file name by using:

Process p;
string filename = p.MainModule.FileName;
shA.t
  • 16,580
  • 5
  • 54
  • 111
Thalur
  • 1,155
  • 9
  • 13
8

By combining Sanjeevakumar Hiremath's and Jeff Mercado's answers you can actually in a way get around the problem when retrieving the icon from a 64-bit process in a 32-bit process.

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

This may be a bit slow and doesn't work on every process which lacks a "valid" icon.

Mc_Topaz
  • 89
  • 1
  • 1
  • This usage might be improved slightly with `string query = "SELECT ExecutablePath, ProcessID FROM Win32_Process WHERE ProcessID = " + process.Id;`... but this method is still quite slow, getting all the results and 'caching' them would be the best speed improvement, if you're getting the path of more than 1 process – Thymine Feb 19 '16 at 21:25
8

Here is a reliable solution that works with both 32bit and 64bit applications.

Add these references:

using System.Diagnostics;

using System.Management;

Add this method to your project:

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

Now use it like so:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Notice that if you know the id of the process, then this method will return the corresponding ExecutePath.

Extra, for those interested:

Process.GetProcesses() 

...will give you an array of all the currently running processes, and...

Process.GetCurrentProcess()

...will give you the current process, along with their information e.g. Id, etc. and also limited control e.g. Kill, etc.*

Community
  • 1
  • 1
WonderWorker
  • 8,539
  • 4
  • 63
  • 74
4

You can use pInvoke and a native call such as the following. This doesn't seem to have the 32 / 64 bit limitation (at least in my testing)

Here is the 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;
    }
Russell Gantman
  • 269
  • 4
  • 7
1

Try:

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.");
}
Lorenz Lo Sauer
  • 23,698
  • 16
  • 85
  • 87
1
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 );  
}
Sonal Satpute
  • 490
  • 3
  • 8
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();
    }

}
Hari Krishna
  • 3,658
  • 1
  • 36
  • 57
0

For others, if you want to find another process of the same executable, you can use:

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;
}
mekb
  • 554
  • 8
  • 22
0

As of .NET 6, you can use Environment.ProcessPath.

In a test, you can see that it gives the same result as Process.GetCurrentProcess().MainModule.FileName:

1

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
0

It's possible to implement process query path using PInvoke on OpenProcess, GetModuleFileNameEx.

See full answer in here.

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
0
using System.Management;
ManagementObjectSearcher search = new ManagementObjectSearcher("SELECT * FROM 
Win32_Process");
        foreach (ManagementObject currentObj in search.Get())
        {
            if (currentObj["Caption"].ToString() == "sqlservr.exe")
            MessageBox.Show(currentObj["ExecutablePath"].ToString());
        }
0

Hello I am not a great programmer, I am just learning by using small blocks of code. I needed to make a small program just to see the path for all running processes by combining WMI code I managed to get what I was looking for. May it will help who is starting with programming like me :) please don’t throw rocks at me :D The main code was provided by Jeff Mercado

class Main
{
  foreach (var item in Process.GetProcesses())
  {

  var result = GetMainModuleFilepath(item.Id);
  if (!string.IsNullOrEmpty(result))
  {
    Console.WriteLine(result + " " + item.Id);
  }

}

string GetMainModuleFilepath(int processId)
{
string wmiQueryString = "SELECT ProcessId, ExecutablePath FROM 
Win32_Process WHERE ProcessId = " + processId;
using (var searcher = new ManagementObjectSearcher(wmiQueryString))
{
    using (var results = searcher.Get())
    {
        ManagementObject mo = results.Cast<ManagementObject> 
().FirstOrDefault();
        if (mo != null)
        {
            return (string)mo["ExecutablePath"];
        }
    }
}
return null;
}
-3

The Process class has a member StartInfo that you should check out:

Daren Thomas
  • 67,947
  • 40
  • 154
  • 200
-4

I got to this thread while looking for the current directory of an executing process. In .net 1.1 Microsoft introduced:

Directory.GetCurrentDirectory();

Seems to work well (but doesn't return the name of the process itself).

Blazemonger
  • 90,923
  • 26
  • 142
  • 180
  • That'll only return the directory the executable is located in under some circumstances. You can, for instance, open a command line, change to any random directory, and run the executable by specifying a full path to it; GetCurrentDirectory() will return the directory you executed from rather than the executable's directory. From [link](http://msdn.microsoft.com/en-us/library/system.io.directory.getcurrentdirectory(v=vs.110).aspx): _"The current directory is distinct from the original directory, which is the one from which the process was started."_ – Dave Ruske Mar 12 '14 at 21:50