Comment puis-je GetModuleFileName () si je n'ai qu'un handle de fenêtre (hWnd)?

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

  •  07-07-2019
  •  | 
  •  

Question

J'essaie d'obtenir le nom de l'exécutable d'une fenêtre située en dehors de mon application C # 2.0. Mon application reçoit actuellement un handle de fenêtre (hWnd) à l'aide de l'appel GetForegroundWindow () à partir de "user32.dll".

D'après les recherches que j'ai pu effectuer, je pense que je souhaite utiliser la fonction GetModuleFileNameEx () (à partir de PSAPI) pour obtenir le nom, mais GetModuleFileNameEx () requiert un descripteur de processus, pas une fenêtre.

Est-il possible d'obtenir un descripteur de processus à partir d'un descripteur de fenêtre? (Dois-je d'abord obtenir le descripteur de thread de la fenêtre?)

MODIFIEZ la première phrase pour préciser ce que j'essaie de faire.

UPDATE! Voici le code C # que j'ai trouvé qui a fonctionné pour moi. Le seul inconvénient est occasionnellement qu'il renvoie un fichier / chemin d'accès où la lettre de lecteur est un "?". au lieu de la lettre de lecteur réelle (comme "C"). - Je n'ai pas encore compris pourquoi.

[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());
}
Était-ce utile?

La solution

Vous pouvez appeler GetWindowThreadProcessId et que vous renverra le processus associé à la fenêtre.

À partir de cela, vous pouvez appeler OpenProcess pour ouvrir le processus. et récupérez le processus.

Autres conseils

Le même problème se pose depuis une heure maintenant, mais la première lettre a également été remplacée par un ? à l'aide de GetModuleFileNameEx. Enfin, cette solution a été développée avec la classe 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;
}

Si vous utilisez une plate-forme Windows 64 bits, vous devrez peut-être utiliser QueryFullProcessImageName. Cela renvoie un chemin de style utilisateur, comparé à GetProcessImageFileName, qui renvoie un chemin de style système devant être converti à l'aide de NtQuerySymbolicLinkObject ou de ZwQuerySymbolicLinkObject.

Un exemple de fonction gigantesque: il est recommandé de décomposer en bits réutilisables.

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

Qu'est-ce que vous essayez exactement de faire? Vous pouvez obtenir l'ID de processus du processus qui a créé une fenêtre avec GetWindowThreadProcessId () , suivi de OpenProcess () pour obtenir le descripteur de processus. Mais cela semble très compliqué, et j’ai le sentiment qu’il existe un moyen plus élégant de faire ce que vous voulez faire.

essayez ceci pour obtenir le nom de fichier de l'exécutable:

C #:

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

merci

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top