Como faço para GetModuleFileName () se eu só tenho um identificador de janela (hWnd)?

StackOverflow https://stackoverflow.com/questions/277085

  •  07-07-2019
  •  | 
  •  

Pergunta

Eu estou tentando obter o nome do executável de uma janela que está fora do meu aplicativo C # 2.0. Meu aplicativo atualmente recebe um identificador de janela (hWnd) utilizando a chamada GetForegroundWindow () de "user32.dll".

A partir da escavação que eu fui capaz de fazer, eu acho que eu quero usar a função GetModuleFileNameEx () (de PSAPI) para obter o nome, mas GetModuleFileNameEx () requer um identificador para um processo, não uma janela.

É possível obter um identificador de processo de um identificador de janela? (Eu preciso para obter o identificador de segmento da janela em primeiro lugar?)

editou a primeira frase para torná-lo mais claro o que estou tentando fazer.

ATUALIZAÇÃO! Aqui está o código C # que eu achei funcionou para mim. A única ressalva é ocasionalmente que retorna um arquivo / caminho onde a letra da unidade é um "?" em vez da letra de unidade real (como "C"). -. Ainda não descobri porque ainda

[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());
}
Foi útil?

Solução

Você pode chamar GetWindowThreadProcessId e que irá retornar o processo associado com a janela.

A partir daí, você pode chamar OpenProcess para abrir o processo de e obter o identificador para o processo.

Outras dicas

sofrido com o mesmo problema por uma hora agora, também tem a primeira letra substituído por um ? usando GetModuleFileNameEx. Finalmente veio com essa solução usando o System.Diagnostics.Process classe.

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

Se você estiver executando em uma plataforma Windows de 64 bits, você pode precisar usar QueryFullProcessImageName vez. Isso retorna um caminho de estilo do usuário, em comparação com GetProcessImageFileName que retorna um caminho estilo sistema que precisam ser convertidos usando NtQuerySymbolicLinkObject ou ZwQuerySymbolicLinkObject.

Um exemplo função de mamute -. Recomendamos quebrando-se em re pedaços utilizáveis ??

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

O que é exatamente isso que você está tentando fazer? Você pode obter o ID do processo do processo que criou uma janela com GetWindowThreadProcessId () , seguido por OpenProcess () para obter o identificador de processo. Mas isso parece muito kludgy, e eu sinto que há uma maneira mais elegante de fazer o que você quer fazer.

tentar isso para obter o nome do arquivo executável:

C #:

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

mfg

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top