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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 10:12:10