2008-11-10 4 views
10

C# 2.0 응용 프로그램 외부에있는 창의 실행 파일 이름을 가져 오려고합니다. 내 응용 프로그램은 현재 "user32.dll"에서 GetForegroundWindow() 호출을 사용하여 창 핸들 (hWnd)을 가져옵니다.창 핸들 (hWnd) 만있는 경우 어떻게 GetModuleFileName()을 수행합니까?

내가 할 수 있었던 파기에서 PSAPI의 GetModuleFileNameEx() 함수를 사용하여 이름을 얻으려고했지만 GetModuleFileNameEx()는 윈도우가 아닌 프로세스의 핸들을 필요로한다고 생각합니다. .

창 핸들에서 프로세스 핸들을 가져올 수 있습니까? (먼저 윈도우의 스레드 핸들을 가져와야합니까?)

내가하려는 것을 명확히하기 위해 첫 번째 문장을 편집했습니다.

업데이트! 다음은 C# 코드입니다. 유일한주의 사항은 인 경우가 종종 있습니다 드라이브 문자가 "?"인 파일/경로를 반환합니다. 실제 드라이브 문자 (예 : "C") 대신. - 아직 이유를 알지 못 했어.

[DllImport("user32.dll")] 
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); 

[DllImport("kernel32.dll")] 
static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId); 

[DllImport("psapi.dll")] 
static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] int nSize); 

[DllImport("kernel32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool CloseHandle(IntPtr hObject); 

private string GetWindowModuleFileName(IntPtr hWnd) 
{ 
    uint processId = 0; 
    const int nChars = 1024; 
    StringBuilder filename = new StringBuilder(nChars); 
    GetWindowThreadProcessId(hWnd, out processId); 
    IntPtr hProcess = OpenProcess(1040, 0, processId); 
    GetModuleFileNameEx(hProcess,IntPtr.Zero,filename,nChars); 
    CloseHandle(hProcess); 
    return (filename.ToString()); 
} 

답변

6

당신은 GetWindowThreadProcessId를 호출 할 수 있습니다 그것은 당신에게 윈도우에 관련 과정을 반환합니다.

그런 다음 OpenProcess으로 전화하여 프로세스를 열고 프로세스의 핸들을 가져올 수 있습니다.

+0

헤이 스택 오버 플로우를 환영

string file = System.Windows.Forms.Application.ExecutablePath; 

제조 - 나는 오랜 시간 독자 봤는데 너 –

1

정확히 무엇을하려는 것입니까? GetWindowThreadProcessId()으로 창을 만든 프로세스의 프로세스 ID를 얻은 다음 OpenProcess()을 입력하여 프로세스 핸들을 얻을 수 있습니다. 그러나 이것은 매우 불투명 해 보이며, 당신이하고 싶은 일을하는보다 우아한 방법이있는 것처럼 느껴집니다.

+0

어쩌면 그것은 너에게 완고한 것처럼 보일지 모르지만, 평판이 1 인 사람은 너보다 1 분 전에 똑같은 대답을 주었고, 나는 그의 평판이 아주 오랫동안 1에 머물러 있다고 생각하지 않는다. –

+0

예, 저도 나에게 기분이 좋습니다. 포커스가있는 창을 추적하려고합니다. 당연히 창 핸들 및 제목 표시 줄 이름은 변경되지만 응용 프로그램 이름은 변경되지 않습니다. – Pretzel

+0

그래도 어쨌든 Larry Osterman이 같은 대답을 주었으므로 모든 대안보다 klugy가 덜하다. 그리고 그의 평판은 더 이상 1이 아닙니다. –

7

한 시간 동안 동일한 문제로 어려움을 겪어 왔으며 첫 번째 문자가 으로 바뀌 었습니까? GetModuleFileNameEx를 사용하여. Finaly는 System.Diagnostics.Process 클래스를 사용하여이 솔루션을 제안했습니다.

[DllImport("user32.dll")] 
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); 

void GetProcessPathFromWindowHandle(IntPtr hwnd) 
{ 
    uint pid = 0; 
    Win32.GetWindowThreadProcessId(hwnd, out pid); 
    Process p = Process.GetProcessById((int)pid); 
    return p.MainModule.FileName; 
} 
+2

나는 이것이 지금까지 제안 된 최선의 해결책이라고 생각한다. 이상한 문자가 없으며 가장 중요한 것은 Windows 7에서 다른 DLL (psapi가 아니라 kernel32)에있는 일관성없는 GetModuleFileNameEx 함수에 의존하지 않는 것입니다. 이 경우 .Net 클래스를 사용하는 것이 좋습니다. 완벽하게 작동합니다. – Axonn

+2

이 스레드는 구식이지만,이 제안 된 솔루션에 대한 작은 의견을 실현합니다. 32 비트 프로세스에서 64 비트 프로세스의 파일 이름을 얻으려고하면 (또는 그 반대로)이 작업은 작동하지 않습니다. – Geoffrey

2

Windows 64 비트 플랫폼에서 실행중인 경우 대신 QueryFullProcessImageName을 사용해야 할 수도 있습니다. NtQuerySymbolicLinkObject 또는 ZwQuerySymbolicLinkObject를 사용하여 변환해야하는 시스템 스타일 경로를 반환하는 GetProcessImageFileName과 비교하여 사용자 스타일 경로를 반환합니다.

하나의 거대한 예제 함수 - 재사용 가능한 비트로 분해 할 것을 권장합니다.

typedef DWORD (__stdcall *PfnQueryFullProcessImageName)(HANDLE hProcess, DWORD dwFlags, LPTSTR lpImageFileName, PDWORD nSize); 
typedef DWORD (__stdcall *PfnGetModuleFileNameEx)(HANDLE hProcess, HMODULE hModule, LPTSTR lpImageFileName, DWORD nSize); 

std::wstring GetExeName(HWND hWnd){ 
// Convert from Window to Process ID 
DWORD dwProcessID = 0; 
::GetWindowThreadProcessId(hWnd, &dwProcessID); 

// Get a handle to the process from the Process ID 
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID); 

// Get the process name 
if (NULL != hProcess) { 
    TCHAR szEXEName[MAX_PATH*2] = {L'\0'}; 
    DWORD nExeName = sizeof(szEXEName)/sizeof(TCHAR); 

    // the QueryFullProcessImageNameW does not exist on W2K 
    HINSTANCE hKernal32dll = LoadLibrary(L"kernel32.dll"); 
    PfnQueryFullProcessImageName pfnQueryFullProcessImageName = NULL; 
    if(hKernal32dll != NULL) { 
     pfnQueryFullProcessImageName = (PfnQueryFullProcessImageName)GetProcAddress(hKernal32dll, "QueryFullProcessImageNameW"); 
     if (pfnQueryFullProcessImageName != NULL) 
      pfnQueryFullProcessImageName(hProcess, 0, szEXEName, &nExeName); 
     ::FreeLibrary(hKernal32dll); 
    } 

    // The following was not working from 32 querying of 64 bit processes 
    // Use as backup for when function above is not available 
    if(pfnQueryFullProcessImageName == NULL){ 
     HINSTANCE hPsapidll = LoadLibrary(L"Psapi.dll"); 
     PfnGetModuleFileNameEx pfnGetModuleFileNameEx = (PfnGetModuleFileNameEx)GetProcAddress(hPsapidll, "GetModuleFileNameExW"); 
     if(pfnGetModuleFileNameEx != NULL)  
      pfnGetModuleFileNameEx(hProcess, NULL, szEXEName, sizeof(szEXEName)/sizeof(TCHAR)); 
     ::FreeLibrary(hPsapidll); 
    } 

    ::CloseHandle(hProcess); 

    return(szEXEName); 
} 
return std::wstring(); 
} 
0

실행 파일의 파일 이름을 얻기 위해이 시도 :

는 C 번호 :

+1

이것은 이전 질문 이었지만, 당시 프로세스 ID를 기반으로 한 다른 프로세스의 EXE 이름을 얻으려고했습니다. (실행 중이던 것이 아닙니다.) 그래서 이것은이 문맥에서 도움이되는 대답이 아닙니다. – Pretzel