3

I'd like to get the name of an application on Windows. Currently I'm using EnumProcesses() to enumerate all processes and receive a list of PIDs.

Then I'm looping through all PIDs, each iteration looks like this, when aProcess[i] is the current PID:

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

My get_process_name(proc) function uses GetModuleFileNameEx to get the executable path and GetProcessImageFileName in order to retrieve the name of the executable file.

What I want to retrieve is basically the App Name, as it is displayed in the Windows Task Manager.

I've looked throughout Win32 API's documentation and could not find a clue on how to achieve this. I've tried looking for other ways such as Windows Shell tasklist but it outputs different things, for example- Google Chrome:

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

I'd really appreciate any thought on the matter, whether it be the Win32 API or some other way I can implement through C++ code.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
Fizban
  • 41
  • 4
  • Are you looking for [this](https://stackoverflow.com/questions/51946787/how-to-extract-file-description-of-executables-using-winapi-and-c)? – Wander3r Oct 12 '20 at 16:20
  • 1
    Windows Task Manager open exe file and look are it have version info, and if yes - read *File description* and display it, instead name of exe – RbMm Oct 12 '20 at 16:21
  • 2
    When opening the process `HANDLE`s, DON'T request `PROCESS_ALL_ACCESS`, you don't need that much permission. `PROCESS_QUERY(_LIMITED)_INFORMATION` will suffice by itself. Also, look at [`QueryFullProcessImageName()`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-queryfullprocessimagenamew). – Remy Lebeau Oct 12 '20 at 16:32

2 Answers2

4

You can do this with GetFileVersionInfoA and VerQueryValueA.

You just need to follow the example given in the VerQueryValueA document.

Here is my sample:

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;
}

And it works for me:

enter image description here

Zeus
  • 3,703
  • 3
  • 7
  • 20
  • 2
    To display the app name for UWP apps, as Task Manager does, as Fizban wants, check whether there's an application user model ID via [`GetApplicationUserModelId`](https://learn.microsoft.com/en-us/windows/win32/api/appmodel/nf-appmodel-getapplicationusermodelid). If so, you can use the shell API to resolve the application display name, e.g. via `SHCreateItemFromParsingName` for "shell:appsfolder\{app_user_model_id}", and call [`GetDisplayName`](https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ishellitem-getdisplayname) with `SIGDN_NORMALDISPLAY`. – Eryk Sun Oct 13 '20 at 06:24
  • 2
    If the code is generalized into a function, make sure to call `CloseHandle(handle)` immediately after calling `GetApplicationUserModelId` (if supporting UWP app names) and `QueryFullProcessImageName`. There's no need to keep the handle open. The code as is will leak the handle if `GetFileVersionInfoSize` fails. – Eryk Sun Oct 13 '20 at 07:14
  • @Fizban Hi,if this answer did help to you, please feel free to mark it to help people with the same issue, and let me know if you have any problem.Thanks. – Zeus Oct 19 '20 at 01:01
2

I think what you want are the "version" resources embedded in the PE file (the executables.)

You seem to be familiar with using Win32 API, so I'm just going to give you some hints.

You have to use LoadLibraryEx to load the EXE file (the Ex suffix is to enable passing the LOAD_LIBRARY_AS_DATAFILE flag,) and then call EnumResourceTypes (also see EnumResourceNames) to enumerate all the resource types/resources in the file, and find what you are looking for and then extract the data with LoadResource. The resource type you want is RT_VERSION.

I'm sure I'm omitting a lot of details (as per usual for Win32 programming,) and there might not be a need for enumeration at all; in which case you may want to call FindResource or FindResourceEx directly (if there is a fixed name for this particular resource.)

As further clarification, this gives you the date you see if you right-click on the EXE file (not the shortcut) in Windows Explorer and select "Properties", then go to the "Details" tab. If that information is indeed what you want (e.g. the "File description" field) then the above method should give you the data.

yzt
  • 8,873
  • 1
  • 35
  • 44