我有一个使用 Toolhelp API 枚举所有进程的程序。使用我的 Sysinternals Process Explorer,我还可以看到所有进程的描述。此描述是否来自可执行文件?我如何得到它的名字?
这是我当前枚举进程的代码:
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <vector>
#include <system_error>
#include <memory>
using namespace std;
vector<PROCESSENTRY32W> getAllProcesses();
int main()
{
for( PROCESSENTRY32W &pe : getAllProcesses() )
wcout << pe.szExeFile << endl;
}
using XHANDLE = unique_ptr<void, decltype([]( HANDLE h ) { h && h != INVALID_HANDLE_VALUE && CloseHandle( h ); })>;
vector<PROCESSENTRY32W> getAllProcesses()
{
auto throwSysErr = []() { throw system_error( (int)GetLastError(), system_category(), "error enumerating processes" ); };
vector<PROCESSENTRY32W> processes;
XHANDLE xhSnapshot( CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ) );
if( xhSnapshot.get() == INVALID_HANDLE_VALUE )
throwSysErr();;
PROCESSENTRY32W pe;
pe.dwSize = sizeof pe;
if( !Process32FirstW( xhSnapshot.get(), &pe ) )
throwSysErr();
for( ; ; )
{
processes.emplace_back( pe );
pe.dwSize = sizeof pe;
if( !Process32NextW( xhSnapshot.get(), &pe ) )
if( GetLastError() == ERROR_NO_MORE_FILES )
break;
else
throwSysErr();
}
return processes;
}
回答1
@RemyLebeau 的代码实现方式改编自 https://docs.microsoft.com/en-us/windows/win32/api/winver/nf-winver-verqueryvaluea#examples 文档示例。正如 https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess#parameters 所说,
如果指定的进程是系统空闲进程(0x00000000),函数失败,最后一个错误码是ERROR_INVALID_PARAMETER。如果指定的进程是系统进程或客户端服务器运行时子系统 (CSRSS) 进程之一,则此函数将失败,最后一个错误代码为 ERROR_ACCESS_DENIED,因为它们的访问限制阻止了用户级代码打开它们。
int main()
{
TCHAR szFile[MAX_PATH] = {};
DWORD dwSize = MAX_PATH;
for (PROCESSENTRY32W& pe : getAllProcesses())
{
wcout << pe.szExeFile << endl;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
FALSE, pe.th32ProcessID);
if (hProcess == NULL)
{
//ErrorExit(TEXT("OpenProcess"));
}
else
{
memset(szFile, 0, MAX_PATH);
dwSize = MAX_PATH;
QueryFullProcessImageName(hProcess,0, szFile,&dwSize);
DWORD s = GetFileVersionInfoSize(szFile,NULL);
if (s != 0)
{
LPVOID lpData = HeapAlloc(GetProcessHeap(), 0, s);
GetFileVersionInfo(szFile,0,s, lpData);
HRESULT hr;
UINT cbTranslate;
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
// Read the list of languages and code pages.
VerQueryValue(lpData,
TEXT("\\VarFileInfo\\Translation"),
(LPVOID*)&lpTranslate,
&cbTranslate);
// Read the file description for each language and code page.
LPVOID lpBuffer;
UINT dwBytes;
for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
{
TCHAR SubBlock[255] = {};
hr = StringCchPrintf(SubBlock, 50,
TEXT("\\StringFileInfo\\%04x%04x\\FileDescription"),
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage);
if (FAILED(hr))
{
// TODO: write error handler.
}
// Retrieve file description for language and code page "i".
VerQueryValue(lpData,
SubBlock,
&lpBuffer,
&dwBytes);
wcout << (TCHAR*)(lpBuffer) << endl;
}
HeapFree(GetProcessHeap(), 0, lpData);
}
//GetProcessImageFileName(hProcess, szFile, dwSize);
}
}
}