如何获取具有可见窗口的任何进程的名称 - 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->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
/ Process32Next
将PROCESSENTRY32.th32ProcessID
与您的idProc
进行比较并使用PROCESSENTRY32.szExeFile
。
另一种更有效的方式使用ZwQuerySystemInformation
和SystemProcessInformation
信息类。比较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) 打开进程并使用ZwQueryInformationProcess
和ProcessImageFileName
(NT 形式的返回路径)或GetProcessImageFileName
(内部调用ZwQueryInformationProcess(,ProcessImageFileName,)
)
或从 vista 开始 - 您可以使用 ProcessImageFileNameWin32
(返回 win32-path)或 QueryFullProcessImageName
(再次仅通过这种方式记录薄壳)
也从 vista 开始 - 查询过程完整路径的最有效方式(以 NT 形式) - 使用 ZwQuerySystemInformation
和 SystemProcessIdInformation
信息类。这种方式不需要任何权限和打开进程
【讨论】:
我不能对这个答案进行足够的投票。做笔记的人...以上是关于如何获取具有可见窗口的任何进程的名称 - WinAPI?的主要内容,如果未能解决你的问题,请参考以下文章