【问题标题】:I want to get the PID of every process I've created in C++ and terminate each after specific time我想获取我在 C++ 中创建的每个进程的 PID,并在特定时间后终止每个进程
【发布时间】:2018-05-07 07:36:37
【问题描述】:

我是 C++ 和 Windows api 的新手。我现在拥有的是我只能打印应用程序第一个进程的 PID。如果我要创建 4 个进程,我想获得他们的 PID;在控制台中打印它并在特定时间后终止它们中的每一个(使用计时)。

样品概览:
1. for process=1 until process=5
2. Call notepad.exe
3. Get the current PID of this process and print in the console.
4. Perform some execution from this processID
5. increment process
6. Whoever successfully executed, terminate the PID.

这是我目前的代码。

#include <iostream>
#include <string>
#include <tchar.h>
#include <process.h>
#include <windows.h>
#include <tlhelp32.h>
#include <stdlib.h>

using namespace std;

//  Forward declarations:
BOOL GetProcessList();
BOOL TerminateMyProcess(DWORD dwProcessId, UINT uExitCode);


int main(void)
{

// Gives info on the thread and process for the new process
PROCESS_INFORMATION pif;

// Defines how to start the program
STARTUPINFO si;

// Zero the STARTUPINFO struct
ZeroMemory(&si, sizeof(si));

// Must set size of structure
si.cb = sizeof(si);

for (int i = 0; i < 3; i++) {

    BOOL bRet = CreateProcess(L"C:\\Users\\notepad.exe", // Path to executable file
        NULL,   // Command string - not needed here
        NULL,   // Process handle not inherited
        NULL,   // Thread handle not inherited
        FALSE,  // No inheritance of handles
        0,      // No special flags
        NULL,   // Same environment block as this prog
        NULL,   // Current directory - no separate path
        &si,    // Pointer to STARTUPINFO
        &pif); // Pointer to PROCESS_INFORMATION

    if (FALSE == bRet)
    {
        MessageBox(HWND_DESKTOP, L"Unable to start program", L"", MB_OK);
        return EXIT_FAILURE;
    }
}

// Close handle to process
CloseHandle(pif.hProcess);

// Close handle to thread
CloseHandle(pif.hThread);

//return EXIT_SUCCESS;
//system("pause");

GetProcessList();
system("pause");
return 0;
}

BOOL GetProcessList()
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;

// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
    return(FALSE);
}

// Set the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);

// Retrieve information about the first process,
// and exit if unsuccessful
if (!Process32First(hProcessSnap, &pe32))
{
    CloseHandle(hProcessSnap);  // clean the snapshot object
    return(FALSE);
}

// Now walk the snapshot of processes 
do
{
    //string str = pe32.szExeFile;
    wchar_t *sample = pe32.szExeFile;
    wstring ws(sample);
    string str(ws.begin(), ws.end());
    //cout << "Haha" << endl;
    if (str == "notepad.exe") // put the name of your process you want to kill
    {
        //print the PID
        cout << "\n" <<pe32.th32ProcessID << endl;
        system("pause");
        TerminateMyProcess(pe32.th32ProcessID, 1);
    }

} while (Process32Next(hProcessSnap, &pe32));

CloseHandle(hProcessSnap);
return(TRUE);
}

BOOL TerminateMyProcess(DWORD dwProcessId, UINT uExitCode)
{
DWORD dwDesiredAccess = PROCESS_TERMINATE;
BOOL  bInheritHandle = FALSE;
HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
if (hProcess == NULL)
    return FALSE;

BOOL result = TerminateProcess(hProcess, uExitCode);

CloseHandle(hProcess);

return result;
}

知道如何让同一应用程序的每个 PID 运行并同时终止它吗?

【问题讨论】:

  • 您根本不需要任何进程 ID。成功创建后你得到了进程的句柄。如果您想稍后终止此过程 - 保存此句柄并使用它调用 TerminateProcess。之后关闭句柄
  • 您的所有代码 - 完全无效。如果您想对您创建的进程执行某些操作 - 将进程句柄保存在某个对象中。当您需要对进程执行某些操作(查询状态、读取内存、终止等)时,请使用此句柄(对象)。当您不再需要此过程时 - 删除对象并在对象析构函数中关闭进程句柄。您根本不需要的进程ID。任何CreateToolhelp32Snapshot 都不需要。
  • @RbMm 我已经修改了我的概述,请检查。
  • 那又怎样?意义和目标不明确。如果您需要对您创建的流程进行处理 - 保存并管理它。全部。如果你需要别的东西 - 你需要问另一个问题

标签: c++ windows winapi process pid


【解决方案1】:

由于PROCESS_INFORMATION pif 包含DWORD dwProcessId 中新创建进程的ID,您可以通过将每个pif.dwProcessId 添加到std::vector&lt;DWORD&gt; processIds 来创建自己的列表。

要终止创建的进程,只需执行类似的操作

for (auto processId : processIds) {
    TerminateMyProcess(processId, 1);
}

编辑:

我想我刚刚意识到使用来自#include &lt;algorithm&gt;std::remove_if 和来自#include &lt;functional&gt;std::bind 的改进。

用这个代替for(auto processId : processIds){...}

processIds.erase(std::remove_if(processIds.begin(), processIds.end(), std::bind(TerminateMyProcess, std::placeholders::_1, 1)));

使用std::remove_if,您可以从容器中删除元素,如果传递的函数(在本例中为TerminateMyProcess)将容器中的元素作为一个参数,返回true。

由于TerminateMyProcess 显然有两个参数DWORDUINT,我们可以使用std::bind 作为TerminateMyProcess 周围的包装函数,它接受一个DWORD 参数(占位符::_1),而UINT 设置为 1

这样,成功终止的 processIds 将从向量中移除,只留下无法终止的 processIds。


另一个反映IInspctable's comment的编辑:

在您的应用程序创建所有这些进程(在您的示例中为 notepad.exe)之后,每个进程都有一个特定的 processId。例如,想象一下,当您的应用程序正在等待终止这些进程的时间时,其中一个已经被终止。该进程的 id 现在不再使用,并且可以由操作系统分配给一个新的、完全不同的进程,这与您的应用程序或 notepad.exe 无关。通常你不想终止任何进程。 ;)

创建一个std::vector&lt;HANDLE&gt; processes
对于每个创建的进程,将pif.hProcess 存储在此向量中。此时不要关闭手柄。 将 TerminateMyProcess 更改为将 HANDLE 作为第一个参数。
使用

processes.erase(std::remove_if(processes.begin(), processes.end(), std::bind(TerminateMyProcess, std::placeholders::_1, 1)));

终止进程并(如果成功终止)从向量中删除它们的句柄。其余句柄可用于错误处理等。


工作示例:

#include <Windows.h>
#include <process.h>

#include <vector>
#include <algorithm>
#include <functional>

#include <chrono>
#include <thread>

std::vector<HANDLE> processes;

void create_process() {
    STARTUPINFO si;
    SecureZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);

    PROCESS_INFORMATION pi;
    SecureZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    if (CreateProcess(L"C:\\windows\\system32\\notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        CloseHandle(pi.hThread);
        processes.push_back(pi.hProcess);
    }
}

BOOL terminate_process(HANDLE handle, UINT exitCode) {
    TerminateProcess(handle, exitCode);
    CloseHandle(handle);

    return TRUE;
}

// Alternative (simplified), makes `std::bind` unnecessary:
BOOL alt_terminate_process(HANDLE handle) {
    TerminateProcess(handle, 1);
    CloseHandle(handle);

    return TRUE;
}

int main()
{
    for (int i = 0; i < 3; ++i) {
        create_process();
    }

    std::this_thread::sleep_for(std::chrono::seconds{ 5 });

    // use either
    processes.erase(std::remove_if(processes.begin(), processes.end(), std::bind(terminate_process, std::placeholders::_1, 1)));
    // or
    processes.erase(std::remove_if(processes.begin(), processes.end(), alt_terminate_process));

    return 0;
}

【讨论】:

  • 也许值得在答案中添加有关问题代码中句柄泄漏的评论。对CloseHandle 的调用必须在循环内。
  • 这还不够。进程 ID 被重用,并且无条件终止具有某些 ID 的进程最终会杀死错误的进程。建议改为存储进程句柄,并在您碰巧需要 ID 时调用GetProcessId
  • @IInspectable 很有趣。你能解释一下你的意思吗?
  • @JAMESBRYANB.Juventud:当一个进程终止时,它的 ID 可用于稍后创建的另一个进程。因此,仅靠进程 ID 不足以唯一标识一个进程。存储句柄(并保留引用)可确保进程对象不会被系统破坏,即使进程已终止。例如,您仍然可以在引用已终止进程的进程句柄上调用 GetExitCodeProcess
  • @IInspectable 感谢您的有用评论。我通过编辑添加了这方面。
猜你喜欢
  • 2017-03-27
  • 2011-02-02
  • 1970-01-01
  • 2012-08-20
  • 2011-02-05
  • 2011-06-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多