如何使用C++或Python获取任务管理器进程页的应用名称
实现方案
任务管理器「进程」选项卡的应用名取值逻辑和「详细信息」页完全不同,不是直接读取exe文件名,目标效果参考:任务管理器进程选项卡示例
取值逻辑说明
任务管理器进程页的应用名按以下优先级获取,和系统原生表现完全对齐:
- 若进程关联已注册的
AppUserModelID(AUMID),优先返回AUMID绑定的注册显示名(适配UWP应用、MSIX打包桌面应用、自定义注册AUMID的软件) - 无有效AUMID时,读取进程主exe文件PE版本资源中的
FileDescription字段 - 以上信息都读取失败时,兜底返回exe文件名,和任务管理器的异常处理逻辑一致
- 若需要和任务管理器一样做同应用多进程归组,额外判断进程父子关系、共享AUMID即可实现
Python 实现
首先安装依赖:pip install pywin32
完整可运行代码:
import win32con import ctypes from ctypes import wintypes kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) version_dll = ctypes.WinDLL('version', use_last_error=True) def get_process_app_name(pid): PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 h_process = kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid) if not h_process: return None # 优先读取AUMID对应显示名 aumid_len = wintypes.DWORD(0) hresult = kernel32.GetApplicationUserModelId(h_process, ctypes.byref(aumid_len), None) if hresult == -2147024774: # 缓冲区不足错误码 aumid_buf = ctypes.create_unicode_buffer(aumid_len.value) if kernel32.GetApplicationUserModelId(h_process, ctypes.byref(aumid_len), aumid_buf) == 0: aumid = aumid_buf.value try: from win32com.propsys import propsys, pscon prop_handler = propsys.PSGetItemPropertyHandler(None, aumid, propsys.GPS_DEFAULT) display_name = prop_handler.GetValue(pscon.PKEY_ItemNameDisplay).GetValue() kernel32.CloseHandle(h_process) return display_name except Exception: pass # 读取exe完整路径 exe_path_len = wintypes.DWORD(260) exe_path_buf = ctypes.create_unicode_buffer(260) if not kernel32.QueryFullProcessImageNameW(h_process, 0, exe_path_buf, ctypes.byref(exe_path_len)): kernel32.CloseHandle(h_process) return None exe_path = exe_path_buf.value kernel32.CloseHandle(h_process) # 读取exe版本资源中的FileDescription try: ver_size = version_dll.GetFileVersionInfoSizeW(exe_path, None) if ver_size == 0: return exe_path.split('\\')[-1].replace('.exe', '') ver_buf = ctypes.create_string_buffer(ver_size) if not version_dll.GetFileVersionInfoW(exe_path, 0, ver_size, ver_buf): return exe_path.split('\\')[-1].replace('.exe', '') translate_ptr = ctypes.c_void_p() translate_len = wintypes.UINT() if not version_dll.VerQueryValueW(ver_buf, r'\VarFileInfo\Translation', ctypes.byref(translate_ptr), ctypes.byref(translate_len)): return exe_path.split('\\')[-1].replace('.exe', '') lang_id, code_page = ctypes.cast(translate_ptr, ctypes.POINTER(ctypes.c_ushort * 2))[0] query_str = f'\\StringFileInfo\\{lang_id:04x}{code_page:04x}\\FileDescription' desc_ptr = ctypes.c_void_p() desc_len = wintypes.UINT() if version_dll.VerQueryValueW(ver_buf, query_str, ctypes.byref(desc_ptr), ctypes.byref(desc_len)) and desc_len.value > 0: return ctypes.wstring_at(desc_ptr) return exe_path.split('\\')[-1].replace('.exe', '') except Exception: return exe_path.split('\\')[-1].replace('.exe', '') if __name__ == '__main__': snapshot = kernel32.CreateToolhelp32Snapshot(win32con.TH32CS_SNAPPROCESS, 0) process_entry = ctypes.Structure.__new__(win32process.PROCESSENTRY32) process_entry.dwSize = ctypes.sizeof(win32process.PROCESSENTRY32) app_set = set() if kernel32.Process32First(snapshot, ctypes.byref(process_entry)): while True: app_name = get_process_app_name(process_entry.th32ProcessID) if app_name: app_set.add(app_name) if not kernel32.Process32Next(snapshot, ctypes.byref(process_entry)): break kernel32.CloseHandle(snapshot) for name in sorted(app_set): print(name)
普通用户权限即可运行,部分系统保护进程会因权限不足跳过,和任务管理器表现一致。
C++ 实现
无需额外依赖,直接调用原生Windows API即可,核心代码如下:
#include <windows.h> #include <tlhelp32.h> #include <appmodel.h> #include <shobjidl_core.h> #include <propsys.h> #include <string> #pragma comment(lib, "version.lib") #pragma comment(lib, "propsys.lib") #pragma comment(lib, "appmodel.lib") std::wstring GetProcessAppName(DWORD pid) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); if (!hProcess) return L""; // 读取AUMID对应显示名 UINT aumidLen = 0; LONG res = GetApplicationUserModelId(hProcess, &aumidLen, nullptr); if (res == ERROR_INSUFFICIENT_BUFFER) { wchar_t* aumid = new wchar_t[aumidLen]; res = GetApplicationUserModelId(hProcess, &aumidLen, aumid); if (res == ERROR_SUCCESS) { IPropertyStore* pps = nullptr; if (SUCCEEDED(SHGetPropertyStoreFromParsingName(aumid, nullptr, GPS_DEFAULT, IID_PPV_ARGS(&pps)))) { PROPVARIANT var; if (SUCCEEDED(pps->GetValue(PKEY_ItemNameDisplay, &var))) { std::wstring ret(var.pwszVal); PropVariantClear(&var); pps->Release(); delete[] aumid; CloseHandle(hProcess); return ret; } pps->Release(); } } delete[] aumid; } // 读取exe路径 wchar_t exePath[MAX_PATH] = {0}; DWORD pathLen = MAX_PATH; if (!QueryFullProcessImageNameW(hProcess, 0, exePath, &pathLen)) { CloseHandle(hProcess); return L""; } CloseHandle(hProcess); // 读取FileDescription DWORD verSize = GetFileVersionInfoSizeW(exePath, nullptr); if (verSize == 0) { wchar_t* exeName = wcsrchr(exePath, L'\\'); return exeName ? exeName + 1 : exePath; } BYTE* verBuf = new BYTE[verSize]; if (!GetFileVersionInfoW(exePath, 0, verSize, verBuf)) { delete[] verBuf; wchar_t* exeName = wcsrchr(exePath, L'\\'); return exeName ? exeName + 1 : exePath; } UINT transLen = 0; struct { WORD lang; WORD codepage; }* trans = nullptr; if (!VerQueryValueW(verBuf, L"\\VarFileInfo\\Translation", (LPVOID*)&trans, &transLen) || transLen < sizeof(*trans)) { delete[] verBuf; wchar_t* exeName = wcsrchr(exePath, L'\\'); return exeName ? exeName + 1 : exePath; } wchar_t subBlock[64] = {0}; swprintf_s(subBlock, L"\\StringFileInfo\\%04x%04x\\FileDescription", trans->lang, trans->codepage); wchar_t* desc = nullptr; UINT descLen = 0; std::wstring ret; if (VerQueryValueW(verBuf, subBlock, (LPVOID*)&desc, &descLen) && descLen > 0) { ret = desc; } else { wchar_t* exeName = wcsrchr(exePath, L'\\'); ret = exeName ? exeName + 1 : exePath; } delete[] verBuf; return ret; } // 枚举进程测试 int main() { HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnap == INVALID_HANDLE_VALUE) return 0; PROCESSENTRY32W pe = {sizeof(pe)}; if (Process32FirstW(hSnap, &pe)) { do { std::wstring name = GetProcessAppName(pe.th32ProcessID); if (!name.empty()) wprintf(L"%s\n", name.c_str()); } while (Process32NextW(hSnap, &pe)); } CloseHandle(hSnap); return 0; }
注意事项
- 不要通过UI自动化读取任务管理器列表获取名称,该方案权限要求高、兼容性差,直接复用系统取值逻辑稳定性最高
- 未写入版本资源、未注册AUMID的第三方程序,任务管理器本身也会显示exe名,上述代码的兜底逻辑和系统表现完全一致
内容的提问来源于stack exchange,提问作者zkz
相关产品推荐
相关产品推荐

