如何获取具有可见窗口的任何进程的名称 - WinAPI?

Posted

技术标签:

【中文标题】如何获取具有可见窗口的任何进程的名称 - WinAPI?【英文标题】:How can I get the name of any process having a visible window - WinAPI? 【发布时间】:2017-04-16 14:40:28 【问题描述】:

我正在尝试获取具有可见窗口的进程的名称。例如,如果我打开了 Chrome,我想获取字符串“chrome.exe”,但我只能使用下面的代码获取初始值“unknown”。

我读到它可能是访问权限问题,您能建议我如何更改它们以获得进程名称吗?

DWORD idProc = 0;       //pointer to the process which created the window
DWORD idThread = GetWindowThreadProcessId(Wnd->get_handle(), &idProc);
Wnd->set_pid(idThread); //Wnd is an object of a class i created, to collect processes info
// Get a handle to the process.
TCHAR szProcessName[DEFAULT_BUFLEN] = TEXT("<unknown>");
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
    PROCESS_VM_READ,
    FALSE, idProc);

if (hProcess!=NULL) 
    HMODULE hMod;
    DWORD cbNeeded;
    if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),
        &cbNeeded))
    
        GetModuleBaseName(hProcess, hMod, szProcessName,        
            sizeof(szProcessName) / sizeof(TCHAR));
    

Wnd->set_processname(szProcessName);                            
CloseHandle(hProcess);

正如我所说,它适用于某些进程,但不适用于 Chrome 等其他许多进程。

编辑:我忘了说,我刚刚过滤了可见窗口,所以假设句柄是我需要的。

【问题讨论】:

您需要添加错误检查,以便您知道哪些调用失败了。 wj32.org/wp/2010/03/30/… 好的,首先感谢您的回答。我添加了一些 std::cout documentation 说:“如果这个函数是从运行在 WOW64 上的 32 位应用程序调用的,它只能枚举 32 位进程的模块。如果该进程是一个 64 位进程,此函数失败,最后一个错误代码是 ERROR_PARTIAL_COPY (299)。" 在任何情况下,您都将窗口的 线程 id 传递给 Wnd-&gt;set_pid(),而您应该传递它的 进程 id。此外,您应该将EnumProcessModules()/GetModuleBaseName() 替换为GetModuleFileNameEx()GetProcessImageFileName()QueryFullProcessImageName()(后两者与PROCESS_QUERY_LIMITED_INFORMATION 一起使用,与PROCESS_QUERY_INFORMATION 相比,您更有可能获得访问权限) )。 【参考方案1】:

改用GetProcessImageNamr API:

#include <iostream>
using namespace std;
#include <windows.h>
#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")


int main()


    DWORD dwProcessId;
    DWORD dwThreadId ;

    while(1)
    
        Sleep(2000);
        HWND hForg = GetForegroundWindow(); // to get the foreground windows' handle window
        dwThreadId = GetWindowThreadProcessId(hForg, &dwProcessId); // getting the window's process ID

        DWORD dwDesiredAccess =
            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
        bool bInheritHandle = false;
        HANDLE hProcess = OpenProcess(dwDesiredAccess,
                                bInheritHandle, dwProcessId);
        if(INVALID_HANDLE_VALUE == hProcess)
            cout << "Failed to open process!" << endl;

        HINSTANCE hMod = (HINSTANCE)GetWindowLongPtr(hForg, GWLP_HINSTANCE);
        if(!hMod)
            cout << "Null Module!" << endl;
        char szModFileName[MAX_PATH] = "";  

    //  never use this cause it won't get you what you want
    //  GetModuleFileNameEx(hProcess, hMod, szModFileName, MAX_PATH);

    //  use this
        GetProcessImageFileName(hProcess, szModFileName, MAX_PATH);

        CloseHandle(hProcess);

        char szWindowName[MAX_PATH] = "";
        GetWindowText(hForg, szWindowName, MAX_PATH);
        cout << "Window Name: " << szWindowName << endl;
        cout << "Created by: " << szModFileName << endl << endl;

    


    cout << endl << endl << endl;
    return 0;

不要使用GetModuleFileNameEx,而是使用GetProcessImageFileName

【讨论】:

PROCESS_QUERY_INFORMATION | PROCESS_VM_READ - 这是错误。主要我们不需要PROCESS_VM_READ。从 vista 开始,我们需要使用 PROCESS_QUERY_LIMITED_INFORMATION 到位 PROCESS_QUERY_INFORMATION 为什么不使用GetModuleFileNameEx而使用GetProcessImageFileName?对我来说,它们产生相同的结果。唯一的区别是驱动器盘符形式的路径,而不是设备。【参考方案2】:

这个问题how get process name/path by ID - 这里已经回答了很多次了。

如果您只需要名称(但不需要完整路径) - 您可以使用 CreateToolhelp32Snapshot / Process32First / Process32NextPROCESSENTRY32.th32ProcessID 与您的idProc 进行比较并使用PROCESSENTRY32.szExeFile

另一种更有效的方式使用ZwQuerySystemInformationSystemProcessInformation 信息类。比较SYSTEM_PROCESS_INFORMATION.UniqueProcessId 和你的idProc 并使用SYSTEM_PROCESS_INFORMATION.ImageName。真正的第一种方法是 shell over this method。

如果您不仅需要名称,还需要完整路径:

如果您有SE_DEBUG_PRIVILEGE - 您需要启用它,使用PROCESS_QUERY_LIMITED_INFORMATION (vista+) 或PROCESS_QUERY_INFORMATION (xp/2003) 打开进程并使用ZwQueryInformationProcessProcessImageFileName(NT 形式的返回路径)或GetProcessImageFileName内部调用ZwQueryInformationProcess(,ProcessImageFileName,)

或从 vista 开始 - 您可以使用 ProcessImageFileNameWin32(返回 win32-path)或 QueryFullProcessImageName再次仅通过这种方式记录薄壳

也从 vista 开始 - 查询过程完整路径的最有效方式(以 NT 形式) - 使用 ZwQuerySystemInformationSystemProcessIdInformation 信息类。这种方式不需要任何权限和打开进程

【讨论】:

我不能对这个答案进行足够的投票。做笔记的人...

以上是关于如何获取具有可见窗口的任何进程的名称 - WinAPI?的主要内容,如果未能解决你的问题,请参考以下文章

C#如何通过进程名称获取指定窗口的句柄,通过该句柄获取该窗口的标题?

已知进程ID,如何获取进程名称 以及路径。

通过镜像名称获取某个进程的进程句柄

如何在 C++ 中按名称获取进程句柄?

如何按名称关闭窗口?

如何在C ++中通过其名称获取进程句柄?