실행중인 프로세스의 전체 경로를 얻는 방법은 무엇입니까?


112

다른 응용 프로그램의 일부 설정을 변경하는 응용 프로그램이 있습니다 (두 번 클릭하여 실행되는 간단한 C # 응용 프로그램 (설정 필요 없음)).

설정을 변경 한 후 변경된 설정을 반영하도록 다른 응용 프로그램을 다시 시작해야합니다.

그러려면 실행중인 프로세스를 종료하고 프로세스를 다시 시작해야하지만 문제는 종료 후 프로세스를 찾을 수 없다는 것입니다. (이유는 시스템이 exe 파일이 어디에 있는지 모릅니다 ..)

실행중인 경우 실행중인 프로세스 또는 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에는 한 가지 문제가 있습니다. 32 비트 애플리케이션에서이 코드를 실행하는 경우 64 비트 애플리케이션 경로에 액세스 할 수 없으므로 64 비트 애플리케이션으로 앱을 컴파일하고 실행해야합니다 ( 프로젝트 속성 → 빌드 → 플랫폼 대상 → x64).


11
@GAPS : 그는 "당신의 프로세스 인스턴스를 얻으십시오. 그러나 당신은 여기서 얻습니다."라고 확신합니다.
Jeff Mercado 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

1
첫 번째 모듈이 메인 모듈이라는 보장이 있습니까?
Sam

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

3
+1 아마도이 질문에 대해서는 과잉이지만 32/64 비트 독립성 때문에이 방법은 실행중인 32 비트 프로세스에서 64 비트 프로세스 정보 를 얻고 싶을 때 정말 유용했습니다 .
마이크 Fuchs의

1
수락 된 답변과 달리 이것은 터미널 서버 환경에서도 작동합니다. 잘 했어, 많이 도왔다!
MC

1
Path속성 집합 mo["ExecutablePath"]null일부 프로세스에 대한 것입니다.
Sam

2
경우 Visual Studio에서 참조 누락에 대해 불평 Process.GetProcesses()하고 results.Cast<>당신은 또한 추가 할 필요가 using System.Linq지시문을.
kibitzerCZ

26

실행중인 프로세스의 프로세스 개체 (예 : GetProcessesByName ())가 이미있는 것 같습니다. 그런 다음 다음을 사용하여 실행 파일 이름을 가져올 수 있습니다.

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

2
사용하지 않는 경우 : var p = Process.GetCurrentProcess (); 문자열 파일 이름 = p.MainModule.FileName;
Andreas

3
"32 비트 프로세스는 64 비트 프로세스의 모듈에 액세스 할 수 없습니다." 불행히도 여기에도 한계가 있습니다.
Roland Pihlakas

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/kernel32.QueryFullProcessImageName
vik_78

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

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

실행중인 프로세스의 현재 디렉터리를 찾는 동안이 스레드에 도착했습니다. .net 1.1에서 Microsoft는 다음을 도입했습니다.

Directory.GetCurrentDirectory();

잘 작동하는 것 같지만 프로세스 자체의 이름을 반환하지 않습니다.


일부 상황에서 실행 파일이있는 디렉토리 만 반환합니다. 예를 들어, 명령 줄을 열고 임의의 디렉토리로 변경 한 다음 전체 경로를 지정하여 실행 파일을 실행할 수 있습니다. GetCurrentDirectory ()는 실행 파일의 디렉토리가 아닌 실행 한 디렉토리를 반환합니다. 에서 링크 : "현재 디렉토리는 프로세스가 시작된 하나입니다 원래 디렉토리로 구별된다."
Dave Ruske 2014 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.