2008-11-10 6 views
10

Ich versuche, den Namen der ausführbaren Datei eines Fensters, das außerhalb meiner C# 2.0-Anwendung ist, zu erhalten. Meine App erhält derzeit ein Fenster-Handle (hWnd) mit dem GetForegroundWindow() - Aufruf von "user32.dll".Wie bekomme ich GetModuleFileName(), wenn ich nur ein Fenster-Handle (hWnd) habe?

Von der Grabung, die ich tun konnte, denke ich, ich möchte die GetModuleFileNameEx() -Funktion (von PSAPI) verwenden, um den Namen zu erhalten, aber GetModuleFileNameEx() erfordert ein Handle zu einem Prozess, kein Fenster .

Ist es möglich, ein Prozesshandle von einem Fensterhandle zu erhalten? (Muss ich zuerst den Thread-Handle des Fensters bekommen?)

EDITED der erste Satz, um es klarer zu machen, was ich versuche zu tun.

UPDATE! Hier ist der C# -Code, den ich gefunden habe, für mich gearbeitet. Die einzige Einschränkung ist gelegentlich es gibt eine Datei/einen Pfad zurück, wo der Laufwerksbuchstabe ein "?" anstelle des tatsächlichen Laufwerksbuchstaben (wie "C"). - Ich habe noch nicht herausgefunden warum.

[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()); 
} 

Antwort

6

können Sie GetWindowThreadProcessId nennen, und das wird Sie den Vorgang mit dem Fenster zugeordnet zurückzukehren.

Von diesem können Sie OpenProcess aufrufen, um den Prozess zu öffnen und das Handle für den Prozess zu erhalten.

+0

Hey willkommen Überlauf zu stapeln - Ich habe eine lange Zeit Leser gewesen deins –

1

Was genau versuchen Sie zu tun? Sie können die Prozess-ID des Prozesses abrufen, der ein Fenster mit GetWindowThreadProcessId() erstellt hat, gefolgt von OpenProcess(), um das Prozess-Handle zu erhalten. Aber das scheint sehr klatschig zu sein, und ich habe das Gefühl, dass es eine elegantere Art gibt, das zu tun, was Sie tun möchten.

+0

Vielleicht scheint es kludgy zu dir, aber jemand mit Ruf von 1 gab die genaue gleiche Antwort nur 1 Minute vor dir, und ich glaube nicht, dass sein Ruf bei 1 für sehr lange bleiben wird. –

+0

Ja, es fühlt sich auch kluggy an. Ich versuche zu verfolgen, welches Fenster den Fokus hat. Natürlich ändern sich die Namen von Fenstergriffen und Titelleisten, der Name der Anwendung wird jedoch nicht geändert. – Pretzel

+0

OK, aber irgendwie hat Larry Osterman die gleiche Antwort gegeben, also ist es wahrscheinlich weniger klugy als alle Alternativen. Und sein Ruf ist nicht mehr 1. –

7

Kämpfen Sie seit einer Stunde mit dem gleichen Problem, hat auch der erste Buchstabe durch eine ersetzt? mithilfe von GetModuleFileNameEx. Endlich kam diese Lösung mit der System.Diagnostics.Process Klasse.

[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

Ich denke, das ist bei weitem die beste Lösung, die hier angeboten wird. Keine seltsamen Zeichen und vor allem nicht die inkonsistente GetModuleFileNameEx-Funktion, die sich unter Windows 7 in einer anderen DLL befindet (nicht psapi, sondern kernel32). Die Verwendung einer .NET-Klasse wird in diesem Fall definitiv bevorzugt. Funktioniert perfekt. – Axonn

+2

Ich realisiere, dass dieser Thread veraltet ist, aber eine kleine Bemerkung zu dieser vorgeschlagenen Lösung. Dies funktioniert nicht, wenn Sie versuchen, den Dateinamen eines 64-Bit-Prozesses von einem 32-Bit-Prozess (oder umgekehrt) zu erhalten. – Geoffrey

2

Wenn Sie auf einer Windows 64-Bit-Plattform ausgeführt werden, müssen Sie stattdessen QueryFullProcessImageName verwenden. Dies gibt einen Pfad zum Benutzerstil im Vergleich zu GetProcessImageFileName zurück, der einen Systemstilpfad zurückgibt, der mithilfe von NtQuerySymbolicLinkObject oder ZwQuerySymbolicLinkObject konvertiert werden müsste.

Eine Mammut-Beispielfunktion - empfehlen, in wiederverwendbare Bits aufzuteilen.

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

dies versuchen, den Dateinamen der ausführbaren Datei zu erhalten:

C#:

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

mfg

+1

Das ist jetzt ein bisschen eine alte Frage, aber zu der Zeit versuchte ich, den EXE-Namen * eines anderen * Prozesses basierend auf der Prozess-ID zu bekommen. (Nicht derjenige, der lief.) Das ist also keine hilfreiche Antwort in diesem Zusammenhang. – Pretzel