実行中のプロセスの完全なパスを取得するにはどうすればよいですか?


112

他のアプリケーションの一部の設定を変更するアプリケーションがあります(ダブルクリックで実行される単純なC#アプリケーションです(セットアップは不要))。

設定を変更した後、他のアプリケーションを再起動して、変更した設定を反映する必要があります。

そのためには、実行中のプロセスを強制終了して再度開始する必要がありますが、問題は強制終了後にプロセスを見つけることができないことです。(理由は、システムがexeファイルの場所を知らないためです。)

実行中のプロセスまたは実行ファイルのパスを確認する方法はありますか?

パスを手動で指定したくありません。つまり、パスが実行されている場合は、パスを取得してプロセスを終了し、もう一度開始します。後で処理します。

回答:


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には1つの問題があります。このコードを32ビットアプリケーションで実行している場合、64ビットアプリケーションパスにアクセスできなくなるため、アプリを64ビットアプリケーションとしてコンパイルして実行する必要があります(プロジェクトのプロパティ→ビルド→プラットフォームターゲット→x64)。


11
@GAPS:彼は「プロセスインスタンスをここで取得してください。
ジェフメルカド2011年

4
問題が発生しstring fullPath = process.Modules[0].FileName;ます。オンラインでアクセスが拒否されました。
Sami

7
Platform Targetをx64に変更する代わりに、Platform TargetをAnyに変更し、Prefer 32ビットオプションオフにしました
Prat

13
私の測定によると、呼び出しprocess.Modules[0]は呼び出しより50倍遅いですprocess.MainModule
Luca Cremonesi 2014年

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 '31 / 03/31

3
+1おそらくこの質問ではやり過ぎですが、32/64ビットの独立性のため、実行中の32ビットプロセスから64ビットプロセスの情報を取得したいときに、この方法が非常に役立ちました。
Mike Fuchs

1
受け入れられた回答とは異なり、これはターミナルサーバー環境でも機能します。お疲れ様でした!
MC

1
Pathから設定されたプロパティmo["ExecutablePath"]null一部のプロセス用であることに注意してください。
サム

2
場合、Visual Studioはのための参照が見つからないとエラーが出るProcess.GetProcesses()results.Cast<>、あなたも追加する必要がありusing System.Linqディレクティブを。
kibitzerCZ 2017年

26

(例えばGetProcessesByName()によって)実行中のプロセスのプロセスオブジェクトがすでにあると思います。次に、以下を使用して実行可能ファイル名を取得できます

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

2
使用しない場合:var p = Process.GetCurrentProcess(); string filename = p.MainModule.FileName;
Andreas

3
「32ビットプロセスは64ビットプロセスのモジュールにアクセスできません。」残念ながらここにも制限があります。
Roland Pihlakas 2013年

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 2015

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

Processこのクラスは、メンバーありStartInfoあなたがチェックアウトする必要があることを。


3
これはProcess.Start()、既存のプロセスではなく、を使用して開始されたローカルプロセスにのみ適用されます。
ジェフメルカード

1
丁度。「このプロセスの開始方法」ではなく、「プロセスの開始方法」です。
Robert Synoradzki 2017

-3

実行中のプロセスの現在のディレクトリを探しているときに、このスレッドにたどり着きました。.net 1.1で、Microsoftは次のことを導入しました。

Directory.GetCurrentDirectory();

うまく機能しているようです(ただし、プロセス自体の名前は返しません)。


これは、特定の状況下で実行可能ファイルが配置されているディレクトリのみを返します。たとえば、コマンドラインを開いて任意のランダムディレクトリに移動し、フルパスを指定して実行可能ファイルを実行できます。GetCurrentDirectory()は、実行可能ファイルのディレクトリではなく、実行元のディレクトリを返します。リンクから:「現在のディレクトリは、プロセスが開始された元のディレクトリとは異なります。」
Dave Ruske
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.