You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 11:21:26