Bagaimana cara mendapatkan jalur lengkap dari proses yang sedang berjalan?


112

Saya memiliki aplikasi yang mengubah beberapa pengaturan aplikasi lain (ini adalah aplikasi C # sederhana yang dijalankan dengan mengklik dua kali (tidak diperlukan pengaturan)).

Setelah mengubah pengaturan, saya perlu memulai ulang aplikasi lain sehingga mencerminkan pengaturan yang diubah.

Jadi untuk melakukannya, saya harus menghentikan proses yang sedang berjalan dan memulai proses lagi, Tetapi masalahnya adalah setelah membunuh saya tidak dapat menemukan prosesnya. (Alasannya adalah sistem tidak tahu di mana file exe itu ..)

Apakah ada cara untuk mengetahui jalur proses yang sedang berjalan atau exe, jika sedang berjalan?

Saya tidak ingin memberikan jalur secara manual, yaitu jika sedang berjalan dapatkan jalurnya, matikan prosesnya dan mulai lagi .... Saya akan tangani nanti

Jawaban:


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.

Ada satu kendala dengan API ini, jika Anda menjalankan kode ini dalam aplikasi 32 bit, Anda tidak akan dapat mengakses jalur aplikasi 64-bit, jadi Anda harus mengkompilasi dan menjalankan aplikasi Anda sebagai aplikasi 64-bit ( Properti Proyek → Bangun → Target Platform → x64).


11
@GAPS: Saya yakin yang dia maksud, "dapatkan contoh proses Anda bagaimanapun Anda mendapatkannya di sini."
Jeff Mercado

4
Ini memberi masalah Akses ditolak secara online string fullPath = process.Modules[0].FileName;Ada ide?
Sami

7
Alih-alih mengubah Target Platform ke x64, saya mengubah Target Platform menjadi Any dan menghapus centang pada opsi Lebih suka 32 bit
Prat

13
Menurut pengukuran saya, panggilan process.Modules[0]adalah 50 kali lebih lambat daripada menelepon process.MainModule.
Luca Cremonesi

1
Apakah ada jaminan bahwa modul pertama adalah modul utama?
Sam

112

Apa yang dapat Anda lakukan adalah menggunakan WMI untuk mendapatkan jalur. Ini akan memungkinkan Anda untuk mendapatkan jalur terlepas dari itu adalah aplikasi 32-bit atau 64-bit. Berikut adalah contoh yang menunjukkan bagaimana Anda bisa mendapatkannya:

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

Perhatikan bahwa Anda harus mereferensikan System.Management.dllrakitan dan menggunakan System.Managementnamespace.

Untuk info selengkapnya tentang informasi lain apa yang dapat Anda ambil dari proses ini seperti baris perintah yang digunakan untuk memulai program ( CommandLine), lihat kelas Win32_Process dan WMI .NET untuk informasi selengkapnya.


1
jawaban Anda luar biasa, tetapi aplikasi saya saat ini kecil ... Saya mengingatnya
PawanS

3
+1 mungkin untuk pertanyaan ini berlebihan, tetapi karena independensi 32 / 64bit, metode ini sangat berguna ketika saya ingin mendapatkan informasi proses 64bit dari proses 32bit yang sedang berjalan .
Mike Fuchs

1
Tidak seperti Answer yang diterima, ini juga berfungsi di Terminal Server Enviroments. Kerja bagus, banyak membantu saya!
MC

1
Perhatikan bahwa Pathset properti dari mo["ExecutablePath"]adalah nulluntuk beberapa proses.
Sam

2
Jika Visual Studio mengeluh tentang referensi yang hilang Process.GetProcesses()dan results.Cast<>Anda juga perlu menambahkan using System.Linqdirektif.
kibitzerCZ

26

Saya kira Anda sudah memiliki objek proses dari proses yang sedang berjalan (misalnya dengan GetProcessesByName ()). Anda kemudian bisa mendapatkan nama file yang dapat dieksekusi dengan menggunakan

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

2
jika tidak digunakan: var p = Process.GetCurrentProcess (); string nama file = p.MainModule.FileName;
Andreas

3
"Proses 32 bit tidak dapat mengakses modul dari proses 64 bit." Batasan sayangnya juga ada di sini.
Roland Pihlakas

18

Solusi untuk:

  • Baik proses 32-bit DAN 64-bit
  • System.Diagnostics saja (tanpa System.Management)

Saya menggunakan solusi dari Russell Gantman dan menulis ulang sebagai metode ekstensi yang dapat Anda gunakan seperti ini:

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

Dengan implementasi ini:

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 mengembalikan BOOL. Kita tidak perlu membandingkannya dengan 0. pinvoke.net/default.aspx/kernel32.QueryFullProcessImageName
vik_78

8

Dengan menggabungkan jawaban Sanjeevakumar Hiremath dan Jeff Mercado, Anda sebenarnya dapat mengatasi masalah saat mengambil ikon dari proses 64-bit dalam proses 32-bit.

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

Ini mungkin agak lambat dan tidak bekerja pada setiap proses yang tidak memiliki ikon "valid".


Penggunaan ini mungkin sedikit ditingkatkan dengan string query = "SELECT ExecutablePath, ProcessID FROM Win32_Process WHERE ProcessID = " + process.Id;... tetapi metode ini masih cukup lambat, mendapatkan semua hasil dan 'menyimpan' mereka akan menjadi peningkatan kecepatan terbaik, jika Anda mendapatkan jalur lebih dari 1 proses
Thymine

8

Berikut adalah solusi andal yang bekerja dengan aplikasi 32bit dan 64bit .

Tambahkan referensi ini:

menggunakan System.Diagnostics;

menggunakan System.Management;

Tambahkan metode ini ke proyek Anda:

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

Sekarang gunakan seperti ini:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Perhatikan bahwa jika Anda mengetahui id proses, maka metode ini akan mengembalikan ExecutePath yang sesuai.

Extra, bagi yang berminat:

Process.GetProcesses() 

... akan memberi Anda array dari semua proses yang sedang berjalan, dan ...

Process.GetCurrentProcess()

... akan memberi Anda proses saat ini, bersama dengan informasinya misalnya Id, dll. Dan juga kontrol terbatas misalnya Bunuh, dll. *


4

Anda dapat menggunakan pInvoke dan panggilan native seperti berikut ini. Ini sepertinya tidak memiliki batasan 32/64 bit (setidaknya dalam pengujian saya)

Ini kodenya

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

Mencoba:

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: ini untuk Majelis Pelaksana (yang saat ini sedang berjalan)
Sonal Satpute

Wow! Terima kasih! Solusi Terbaik yang pernah ada, karena berfungsi bahkan di 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

Bagi orang lain, jika Anda ingin mencari proses lain dari eksekusi yang sama, Anda dapat menggunakan:

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

Saya sampai di utas ini sambil mencari direktori saat ini dari proses eksekusi. Dalam .net 1.1 Microsoft memperkenalkan:

Directory.GetCurrentDirectory();

Tampaknya berfungsi dengan baik (tetapi tidak mengembalikan nama proses itu sendiri).


Itu hanya akan mengembalikan direktori tempat eksekusi berada dalam beberapa keadaan. Anda dapat, misalnya, membuka baris perintah, mengubah ke direktori acak mana pun, dan menjalankan file yang dapat dieksekusi dengan menentukan jalur lengkap ke sana; GetCurrentDirectory () akan mengembalikan direktori tempat Anda dieksekusi daripada direktori yang dapat dieksekusi. Dari tautan : "Direktori saat ini berbeda dari direktori asli, yang merupakan tempat proses dimulai."
Dave Ruske
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.