Search code examples
c++windowswinapiprocesspid

I want to get the PID of every process I've created in C++ and terminate each after specific time


I'm new in C++ and Windows api. What I have right now is that I can print only the PID of the first process of the application. If I'll create say 4 process, I want to get their PID's; print it in console and terminate each one of them after specific time(using chrono).

Sample Overview:
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.

Here is my code so far.

#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;
}

Any idea on how I can get every PID of the same application running and terminate it concurrently?


Solution

  • As PROCESS_INFORMATION pif contains the id of the newly created process in DWORD dwProcessId, you could for instance create your own list by adding each pif.dwProcessId to a std::vector<DWORD> processIds.

    And to terminate the created processes, just do something like

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

    Edit:

    I think I just realised an improvement using std::remove_if from #include <algorithm> and std::bind from #include <functional>.

    Instead of for(auto processId : processIds){...} use this:

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

    With std::remove_if you can erase elements from a container, if a passed function (in this case TerminateMyProcess), that takes as it's one argument an element from the container, returns true.

    As TerminateMyProcess obviously has two arguments, DWORD and UINT, we can use std::bind as a wrapper function around TerminateMyProcess that takes one DWORD argument (placeholders::_1) while the UINT is set to be 1.

    This way, successfully terminated processIds will be removed from the vector, leaving only the processIds, that could not be terminated.


    Another edit to reflect IInspctable's comment:

    After your application created all these processes (notepad.exe in your example), each of them has a specific processId. Imagine, for example, while your application is waiting for the time to terminate these processes, one of them already gets terminated. The process's id is now no longer in use and can be assigned by the operating system to a new and completely different process, that has nothing to do with your application or notepad.exe. Usually you don't want to terminate just any process. ;)

    Create one std::vector<HANDLE> processes.
    For each created process, store pif.hProcess in this vector. Do not close the handle at this point. Change TerminateMyProcess that it takes a HANDLE as it's first argument.
    Use

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

    to terminate processes and (if successfully terminated) remove their handles from the vector. The remaining handles can be used for error handling etc.


    Working example:

    #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;
    }