【问题标题】:How can I get a process handle by its name in C++?如何在 C++ 中按名称获取进程句柄?
【发布时间】:2010-10-26 07:04:43
【问题描述】:

我正在尝试获取 example.exe 的进程句柄,因此我可以在其上调用 TerminateProcess。我怎样才能做到这一点?注意,它没有窗口,所以FindWindow 不起作用。

【问题讨论】:

    标签: c++ winapi process


    【解决方案1】:
    #include <cstdio>
    #include <windows.h>
    #include <tlhelp32.h>
    
    int main( int, char *[] )
    {
        PROCESSENTRY32 entry;
        entry.dwSize = sizeof(PROCESSENTRY32);
    
        HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    
        if (Process32First(snapshot, &entry) == TRUE)
        {
            while (Process32Next(snapshot, &entry) == TRUE)
            {
                if (stricmp(entry.szExeFile, "target.exe") == 0)
                {  
                    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
    
                    // Do stuff..
    
                    CloseHandle(hProcess);
                }
            }
        }
    
        CloseHandle(snapshot);
    
        return 0;
    }
    

    另外,如果你想在 OpenProcess 中使用 PROCESS_ALL_ACCESS,你可以试试这个:

    #include <cstdio>
    #include <windows.h>
    #include <tlhelp32.h>
    
    void EnableDebugPriv()
    {
        HANDLE hToken;
        LUID luid;
        TOKEN_PRIVILEGES tkp;
    
        OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
    
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
    
        tkp.PrivilegeCount = 1;
        tkp.Privileges[0].Luid = luid;
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
        AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), NULL, NULL);
    
        CloseHandle(hToken); 
    }
    
    int main( int, char *[] )
    {
        EnableDebugPriv();
    
        PROCESSENTRY32 entry;
        entry.dwSize = sizeof(PROCESSENTRY32);
    
        HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    
        if (Process32First(snapshot, &entry) == TRUE)
        {
            while (Process32Next(snapshot, &entry) == TRUE)
            {
                if (stricmp(entry.szExeFile, "target.exe") == 0)
                {  
                    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
    
                    // Do stuff..
    
                    CloseHandle(hProcess);
                }
            }
        }
    
        CloseHandle(snapshot);
    
        return 0;
    }
    

    【讨论】:

    • 您的代码将跳过系统中的第一个进程(但是,第一个进程很可能是“SYSTEM”,因此没有用户可见的错误。)
    • 将其更改为: HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION + PROCESS_VM_READ + PROCESS_TERMINATE, FALSE, entry.th32ProcessID );我会给你答案
    • 我已经能够从这个答案中取得很大进展 - 非常感谢所有做出贡献的人。不过,我遇到了权限问题。即使使用 EnableDebugPriv,当我尝试打开不属于我自己的进程时,“我的 OpenProcess 失败并出现错误 5(访问被拒绝)”。就我而言,我正在寻找所有用户的 iexplore。
    • 优秀的答案!在 Unicode 和 ANSI 编译标志之间切换时,您应该将行 if (stricmp(entry.szExeFile, "target.exe") == 0) 更改为 if (_tcsicmp(entry.szExeFile, _T("target.exe")) == 0) 以保持类型完整性。
    • 对于像我这样喜欢按字母顺序排列标题的人的注意事项 -- windows.h 必须在 tlhelp32.h 之前包含,否则您最终会遇到关于未定义函数的令人困惑的错误(因为定义取决于windows.h)
    【解决方案2】:

    以下代码显示了如何使用 toolhelp 和 OpenProcess 来获取进程的句柄。为简洁起见,删除了错误处理。

    HANDLE GetProcessByName(PCSTR name)
    {
        DWORD pid = 0;
    
        // Create toolhelp snapshot.
        HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        PROCESSENTRY32 process;
        ZeroMemory(&process, sizeof(process));
        process.dwSize = sizeof(process);
    
        // Walkthrough all processes.
        if (Process32First(snapshot, &process))
        {
            do
            {
                // Compare process.szExeFile based on format of name, i.e., trim file path
                // trim .exe if necessary, etc.
                if (string(process.szExeFile) == string(name))
                {
                   pid = process.th32ProcessID;
                   break;
                }
            } while (Process32Next(snapshot, &process));
        }
    
        CloseHandle(snapshot);
    
        if (pid != 0)
        {
             return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
        }
    
        // Not found
    
    
           return NULL;
    }
    

    【讨论】:

    • 您在“if (MatchProcessName(process.szExeFile, name)”条件中忘记了一个括号。
    • 就像 xian 的回答一样,这有一个竞争条件,本质上是不安全的。
    • @Occulta if (string(process.szExeFile) == string(name)) 可以用来代替这个函数。我编辑了迈克尔的答案。
    【解决方案3】:

    有两种基本技术。第一个使用PSAPI; MSDN 有 an example 使用 EnumProcessesOpenProcessEnumProcessModulesGetModuleBaseName

    另一个使用我更喜欢的 Toolhelp。使用CreateToolhelp32Snapshot获取进程列表的快照,使用Process32FirstProcess32Next遍历它,提供模块名称和进程ID,直到找到你想要的,然后调用OpenProcess获取一个处理。

    【讨论】:

      【解决方案4】:

      可以使用以下代码:

      DWORD FindProcessId(const std::wstring& processName)
      {
          PROCESSENTRY32 processInfo;
          processInfo.dwSize = sizeof(processInfo);
      
          HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
          if (processesSnapshot == INVALID_HANDLE_VALUE) {
              return 0;
          }
      
          Process32First(processesSnapshot, &processInfo);
          if (!processName.compare(processInfo.szExeFile))
          {
              CloseHandle(processesSnapshot);
              return processInfo.th32ProcessID;
          }
      
          while (Process32Next(processesSnapshot, &processInfo))
          {
              if (!processName.compare(processInfo.szExeFile))
              {
                  CloseHandle(processesSnapshot);
                  return processInfo.th32ProcessID;
              }
          }
      
          CloseHandle(processesSnapshot);
          return 0;
      }
      

      用法:

      auto processId = FindProcessId(L"blabla.exe");
      

      获取句柄应该是显而易见的,只需调用OpenProcess() 或类似名称即可。

      【讨论】:

        【解决方案5】:

        查看:MSDN Article

        您可以使用GetModuleName(我认为?)来获取名称并进行检查。

        【讨论】:

        • 大多数 GetModuleName、QueryFullProcessImage 名称等都需要句柄,因此没有多大用处。 Toolhelp 确实返回进程名称。
        【解决方案6】:

        OpenProcess函数

        来自 MSDN:

        要打开另一个本地进程的句柄并获得完全访问权限,您必须启用 SeDebugPrivilege 权限。

        【讨论】:

        • 我没有 pID,只有名字。
        • SeDebugPrivilege 对于像你一样运行的进程绝对不需要。如果您可以通过它的 ACL 访问该进程(通常对您创建的与您的代码具有相同完整性级别的进程进行访问),则不需要 SeDebugPrivilege。来自同一 MSDN 页面:如果调用者启用了 SeDebugPrivilege 权限,则无论安全描述符的内容如何,​​都会授予请求的访问权限。
        • 是的,你需要先通过迭代进程来获取进程ID。
        【解决方案7】:

        如果您不介意使用system(),那么使用system("taskkill /f /im process.exe") 会比这些其他方法容易得多。

        【讨论】:

          猜你喜欢
          • 2015-03-07
          • 2011-06-16
          • 2011-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多