Как мне получить GetModuleFileName (), если у меня есть только дескриптор окна (hWnd)? - PullRequest
10 голосов
/ 10 ноября 2008

Я пытаюсь получить имя исполняемого файла окна, которое находится за пределами моего приложения C # 2.0. В настоящее время мое приложение получает дескриптор окна (hWnd) с помощью вызова GetForegroundWindow () из "user32.dll".

Из копания, которое я смог сделать, я думаю, что хочу использовать функцию GetModuleFileNameEx () (из PSAPI) для получения имени, но 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());
}

Ответы [ 5 ]

8 голосов
/ 26 ноября 2008

В течение часа боролся с той же проблемой, а также заменил первую букву на ? с помощью GetModuleFileNameEx. Наконец, это решение было разработано с использованием класса 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;
}
6 голосов
/ 10 ноября 2008

Вы можете вызвать GetWindowThreadProcessId , и это вернет вам процесс, связанный с окном.

После этого вы можете вызвать OpenProcess , чтобы открыть процесс и получить дескриптор процесса.

2 голосов
/ 11 февраля 2009

Если вы работаете на 64-битной платформе Windows, вам может потребоваться вместо этого использовать QueryFullProcessImageName. Это возвращает путь стиля пользователя, по сравнению с GetProcessImageFileName, который возвращает путь стиля системы, который должен быть преобразован с использованием NtQuerySymbolicLinkObject или ZwQuerySymbolicLinkObject.

Пример одной гигантской функции - рекомендуем разбивать на биты многократного использования.

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();
}
1 голос
/ 10 ноября 2008

Что именно вы пытаетесь сделать? Вы можете получить идентификатор процесса, который создал окно, с помощью GetWindowThreadProcessId () , за которым следует OpenProcess () для получения дескриптора процесса. Но это кажется очень грязным, и я чувствую, что есть более элегантный способ делать то, что вы хотите сделать.

0 голосов
/ 31 мая 2010

попробуйте это, чтобы получить имя файла исполняемого файла:

C #:

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

MFG

...