【问题标题】:C++ Win32 - Getting App Name using PID and Executable PathC++ Win32 - 使用 PID 和可执行路径获取应用程序名称
【发布时间】:2020-10-12 15:45:14
【问题描述】:

我想获取 Windows 上的应用程序的名称。 目前我正在使用EnumProcesses() 枚举所有进程并接收 PID 列表。

然后我循环遍历所有 PID,每次迭代看起来像这样,当 aProcess[i] 是当前 PID:

HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, aProcesses[i]);
std::string processName = get_process_name(proc);

我的get_process_name(proc) 函数使用GetModuleFileNameEx 来获取可执行文件路径,并使用GetProcessImageFileName 来检索可执行文件的名称。

我要检索的基本上是应用程序名称,因为它显示在 Windows 任务管理器中。

我查看了整个 Win32 API 的文档,但找不到有关如何实现此目的的线索。 我尝试寻找其他方式,例如 Windows Shell 任务列表,但它输出不同的东西,例如 - Google Chrome:

Image Name: chrome.exe PID: 84 Session Name: Console

我非常感谢您对此事的任何想法,无论是 Win32 API 还是我可以通过 C++ 代码实现的其他方式。

【问题讨论】:

  • 您在寻找this吗?
  • Windows 任务管理器打开 exe 文件并查看它是否有版本信息,如果有 - 阅读 文件描述 并显示它,而不是 exe 的名称
  • 打开进程HANDLEs时,不要请求PROCESS_ALL_ACCESS,你不需要那么多权限。 PROCESS_QUERY(_LIMITED)_INFORMATION 本身就足够了。另外,请查看QueryFullProcessImageName()

标签: c++ windows powershell winapi


【解决方案1】:

您可以使用GetFileVersionInfoAVerQueryValueA 来做到这一点。

您只需要按照VerQueryValueA 文档中给出的示例进行操作即可。

这是我的示例:

struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;

int main()
{
    HANDLE handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION , FALSE, 2140);   //Modify pid to the pid of your application
    if (!handle) return 0;
    wchar_t pszFile[MAX_PATH] = L"";
    DWORD len = MAX_PATH;
    QueryFullProcessImageName(handle, 0, pszFile, &len);
    UINT dwBytes, cbTranslate;
    DWORD dwSize = GetFileVersionInfoSize(pszFile, (DWORD*)&dwBytes);
    if (dwSize == 0) return 0;
    LPVOID lpData = (LPVOID)malloc(dwSize);
    ZeroMemory(lpData, dwSize);
    if (GetFileVersionInfo(pszFile, 0, dwSize, lpData))
    {
        VerQueryValue(lpData,
            L"\\VarFileInfo\\Translation",
            (LPVOID*)&lpTranslate,
            &cbTranslate);
        wchar_t strSubBlock[MAX_PATH] = { 0 };
        wchar_t* lpBuffer;

        for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
        {
            StringCchPrintf(strSubBlock,50,
                L"\\StringFileInfo\\%04x%04x\\FileDescription",
                lpTranslate[i].wLanguage,
                lpTranslate[i].wCodePage);
            VerQueryValue(lpData,
                strSubBlock,
                (void**)&lpBuffer,
                &dwBytes);
            std::wcout << lpBuffer << std::endl;
        }
    }
    if(lpData) free(lpData);
    if (handle) CloseHandle(handle);
    return 0;
}

它对我有用:

【讨论】:

  • 要显示 UWP 应用程序的应用程序名称,如任务管理器那样,如 Fizban 所愿,通过GetApplicationUserModelId 检查是否有应用程序用户模型 ID。如果是这样,您可以使用 shell API 来解析应用程序显示名称,例如通过SHCreateItemFromParsingName 获取“shell:appsfolder\{app_user_model_id}”,并使用SIGDN_NORMALDISPLAY 调用GetDisplayName
  • 如果将代码泛化为函数,请确保在调用GetApplicationUserModelId(如果支持UWP应用名称)和QueryFullProcessImageName之后立即调用CloseHandle(handle)。无需保持手柄打开。如果GetFileVersionInfoSize 失败,代码将泄漏句柄。
  • @Fizban 嗨,如果这个答案对你有帮助,请随时标记它以帮助有同样问题的人,如果你有任何问题,请告诉我。谢谢。
【解决方案2】:

我认为您想要的是嵌入在 PE 文件(可执行文件)中的“版本”资源。

您似乎对使用 Win32 API 很熟悉,所以我只是给您一些提示。

您必须使用LoadLibraryEx 加载EXE 文件(Ex 后缀是启用传递LOAD_LIBRARY_AS_DATAFILE 标志,)然后调用EnumResourceTypes(另见EnumResourceNames)枚举所有资源类型/文件中的资源,找到您要查找的内容,然后使用LoadResource 提取数据。你想要的资源类型是RT_VERSION

我确定我省略了很多细节(按照 Win32 编程的惯例),并且可能根本不需要枚举;在这种情况下,您可能需要直接调用FindResourceFindResourceEx(如果此特定资源有固定名称。)

作为进一步的说明,如果您在 Windows 资源管理器中右键单击 EXE 文件(不是快捷方式)并选择“属性”,然后转到“详细信息”选项卡,这将为您提供看到的日期。如果该信息确实是您想要的(例如“文件描述”字段),那么上述方法应该为您提供数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-09
    • 2019-09-28
    • 2016-12-18
    • 1970-01-01
    相关资源
    最近更新 更多