如何用C++获取Windows服务的内存使用情况?
解决Windows服务内存获取时OpenProcess权限拒绝问题
我正在寻找使用C++获取Windows服务内存使用情况的示例,已搜索论坛、谷歌及微软文档,但未找到相关信息。我已有获取服务PID的代码,尝试使用GetProcessMemoryInfo函数时,OpenProcess返回空句柄,即使以管理员权限运行程序,GetLastError仍返回“access denied”。以下是我的相关代码:
编译命令
cl /EHsc TheProgram.cpp Advapi32.lib
头文件引用
#include <windows.h> #include <vector> #include <iostream> #include <string> #include <winsvc.h>
查找服务的函数
int FindServices(const std::string &ServiceNameToFind) { SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT); if (hSCM == NULL)return 0; DWORD bufferSize = 0; DWORD requiredBufferSize = 0; DWORD totalServicesCount = 0; EnumServicesStatusEx( hSCM, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, nullptr, bufferSize, &requiredBufferSize, &totalServicesCount, nullptr, nullptr ); std::vector<BYTE> buffer( requiredBufferSize ); EnumServicesStatusEx( hSCM, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, buffer.data(), buffer.size(), &requiredBufferSize, &totalServicesCount, nullptr, nullptr ); int result = 0; LPENUM_SERVICE_STATUS_PROCESS services = reinterpret_cast<LPENUM_SERVICE_STATUS_PROCESS>( buffer.data() ); for ( unsigned int i = 0; i < totalServicesCount; ++i ) { ENUM_SERVICE_STATUS_PROCESS service = services[i]; std::string CurrentServiceName(service.lpServiceName); std::size_t found = CurrentServiceName.find(ServiceNameToFind); if (found==std::string::npos) continue; DWORD processID = service.ServiceStatusProcess.dwProcessId; std::cout <<service.lpServiceName<<" "<< processID <<std::endl; result++; } CloseServiceHandle( hSCM ); return result; }
主函数
int main( void ) { std::string ServiceName("TheService"); FindServices(ServiceName); system("Pause"); return 0; }
尝试获取内存信息的函数
void PrintMemoryInfo( DWORD processID ) { HANDLE hProcess; PROCESS_MEMORY_COUNTERS pmc; hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ); if (NULL == hProcess) { return; std::cout<< "OpenProcess() FAIL ->" <<GetLastErrorStdStr() <<std::endl; } if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) ) { std::cout<< "PageFaultCount: ->" << pmc.PageFaultCount <<std::endl; std::cout<< "PeakWorkingSetSize: ->" << pmc.PeakWorkingSetSize <<std::endl; std::cout<< "WorkingSetSize: ->" << pmc.WorkingSetSize <<std::endl; std::cout<< "QuotaPeakPagedPoolUsage: ->" << pmc.QuotaPeakPagedPoolUsage <<std::endl; std::cout<< "QuotaPagedPoolUsage: ->" << pmc.QuotaPagedPoolUsage <<std::endl; std::cout<< "QuotaPeakNonPagedPoolUsage: ->" << pmc.QuotaPeakNonPagedPoolUsage <<std::endl; std::cout<< "QuotaNonPagedPoolUsage: ->" << pmc.QuotaNonPagedPoolUsage <<std::endl; std::cout<< "PagefileUsage: ->" << pmc.PagefileUsage <<std::endl; std::cout<< "PeakPagefileUsage: ->" << pmc.PeakPagefileUsage <<std::endl; ); } CloseHandle( hProcess ); }
错误信息转换函数
std::string GetLastErrorStdStr() { DWORD error = GetLastError(); if (error) { LPVOID lpMsgBuf; DWORD bufLen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); if (bufLen) { LPCSTR lpMsgStr = (LPCSTR)lpMsgBuf; std::string result(lpMsgStr, lpMsgStr+bufLen); LocalFree(lpMsgBuf); return result; } } return std::string(); }
问题解决方法
1. 替换进程查询权限
从Windows 7开始,PROCESS_QUERY_LIMITED_INFORMATION权限比PROCESS_QUERY_INFORMATION更容易获取,且完全满足GetProcessMemoryInfo的调用需求。修改PrintMemoryInfo中的OpenProcess调用:
hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processID);
2. 启用调试权限(针对SYSTEM级服务)
部分系统服务以SYSTEM权限运行,管理员账号需额外启用调试权限才能打开其进程句柄。添加如下函数并在主函数开头调用:
BOOL EnableDebugPrivilege() { HANDLE hToken; TOKEN_PRIVILEGES tp; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return FALSE; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); CloseHandle(hToken); return (GetLastError() == ERROR_SUCCESS); }
修改主函数:
int main(void) { EnableDebugPrivilege(); std::string ServiceName("TheService"); FindServices(ServiceName); system("Pause"); return 0; }
3. 修复语法错误
PrintMemoryInfo函数末尾有多余的);,删除后才能正常编译。
4. 关联内存查询函数
在FindServices函数中找到服务PID后,调用PrintMemoryInfo:
DWORD processID = service.ServiceStatusProcess.dwProcessId; std::cout << service.lpServiceName << " " << processID << std::endl; PrintMemoryInfo(processID); result++;
内容的提问来源于stack exchange,提问作者Iván Rodríguez
相关产品推荐
相关产品推荐

