0

The following code works to "kill -9" my process (see below). But I prefer to not shell out to cmd.exe just to kill a process from my C++ program. Is there a pure Win32 API way of doing this, specifically, with the effects of the "/T and /F" flags. I got to believe its possible since taskkill.exe was writtend in Win32 API.

    #include <iostream>
    #include <string>

    void KillDash9(unsigned long PID) {
        std::string killcmd = std::string("") 
                            + std::string("taskkill /T /F /PID ") 
                            + std::to_string(PID);
        std::cout << killcmd << std::endl;
        system(killcmd.c_str());
    }

Here's what I tried that didn't work:

void KillDash9_v2(unsigned long PID) {
    HANDLE pHandle = OpenProcess(
    /*[in] DWORD dwDesiredAccess*/ PROCESS_TERMINATE | SYNCHRONIZE,
    /*[in] BOOL  bInheritHandle*/  TRUE,
    /*[in] DWORD dwProcessId*/     PID
    );
    TerminateProcess(pHandle, 0);
    WaitForSingleObject(pHandle, 500);
    CloseHandle(pHandle);
}
 

KillDash9_v2() won't kill the process:

"powershell -command ping -t localhost"  

enter image description here

However, KillDash9_v1() works to kill this process.

How to get KillDash9_v2() to work the same way? v2 will kill powershell (3328) but it won't kill ping.exe (7236) which keeps running after killing 7236. I need to somehow enumerate the process tree starting 7246 and kill each branch under it.

I added in error checking as suggested.

void KillDash9_v3(unsigned long PID) {

    // Clear Windows Error Variable
    SetLastError(0);

    HANDLE pHandle = OpenProcess(
    /*[in] DWORD dwDesiredAccess*/ PROCESS_TERMINATE | SYNCHRONIZE,
    /*[in] BOOL  bInheritHandle*/  FALSE,
    /*[in] DWORD dwProcessId*/     PID
    );
    if (pHandle == nullptr) {
        long int err = GetLastError();
        std::string msg = std::string("ERROR  : OpenProcess failed for PID(") + std::to_string(PID) + std::string(")\n")
                        + std::string("REASON : ") + WindowsGetErrorString(err) + std::string("\n")
                        + std::string("CODE   : ") + std::to_string(err) + std::string("\n");
        std::cout << msg;
        return;
    }

    // Clear Windows Error Variable
    SetLastError(0);

    BOOL rc = TerminateProcess(pHandle, 0);
    if (rc == 0) {
        long int err = GetLastError();
        std::string msg = std::string("ERROR:  TerminateProcess failed for PID(") + std::to_string(PID) + std::string(")\n")
                   + std::string("REASON: ") + WindowsGetErrorString(err) + std::string("\n")
                   + std::string("CODE   : ") + std::to_string(err) + std::string("\n");
        std::cout << msg;
        return;
    }

    WaitForSingleObject(pHandle, 500);
    CloseHandle(pHandle);
}
pico
  • 1,660
  • 4
  • 22
  • 52
  • You should check if the handle returned by `OpenProcess` is valid or not. Go through it's documentation – Asesh Dec 01 '21 at 03:47
  • Its got to be value because it works for taskkill.exe... why wouldn't TerminateProcess be the same PID? – pico Dec 01 '21 at 03:49
  • Because of process access rights, `OpenProcess` might fail. That's why you should check if the handle returned by it is valid or not. – Asesh Dec 01 '21 at 03:53
  • good suggestion... i'll give it a try. – pico Dec 01 '21 at 04:12
  • I tryed it. OpenProcess fails with 87 (The parameter is incorrect.) But i get the PID from process_info.dwProcessId from a CreateProcess? should work? – pico Dec 01 '21 at 04:30
  • when i search for the PID using powershell command: Get-Process -Id . It shows up?? Why can't I openprocess to that PID if it exists? – pico Dec 01 '21 at 04:40
  • You should look at this thread: https://stackoverflow.com/questions/4988082/openprocess-error-87-invalid-parameter – Asesh Dec 01 '21 at 04:55
  • @pico If you are being given a process ID from `CreateProcess...()`, then you are also given a `HANDLE` to that same process (in `process_info.hProcess`), so you don't need to use `OpenProcess()` at all, just use the `HANDLE` you already have. You have full rights to any process you spawn with `CreateProcess()`, so you can kill it with `TerminateProcess()`. Simply don't close the `HANDLE` until the process exits. – Remy Lebeau Dec 01 '21 at 19:16
  • 1
    @pico There is a much easier way to kill a spawned tree of processes, though. When spawning a new process with `CreateProcess...()`, put the new process into a job object. Any child processes it creates will also be put into the same job (by default, can be overridden). Then you can simply [terminate the job object](https://learn.microsoft.com/en-us/windows/win32/api/jobapi2/nf-jobapi2-terminatejobobject). – Remy Lebeau Dec 01 '21 at 19:22

1 Answers1

1
void ProcessKillTree_v1(unsigned long PARENT_PID)
{
    std::string killcmd = std::string("") 
          + std::string("taskkill /T /F /PID ") 
          + std::to_string(PARENT_PID);
    std::cout << killcmd << std::endl;
    system(killcmd.c_str());
}
void ProcessKillTree_v2(unsigned long PARENT_PID)
{
    if(PARENT_PID > 0) {

        // Kill Tree
        HANDLE snapshot = CreateToolhelp32Snapshot(
            TH32CS_SNAPPROCESS, 0);

        if(snapshot) {
            PROCESSENTRY32 process;
            ZeroMemory(&process, sizeof(process));
            process.dwSize = sizeof(process);

            if(Process32First(snapshot, &process)) {
                do {
                    if(process.th32ParentProcessID==PARENT_PID) {
                        HANDLE process_handle 
                             = OpenProcess(
                                  PROCESS_TERMINATE, 
                                  FALSE, 
                                  process.th32ProcessID
                             );

                        if(process_handle) {
                            ProcessKillTree(process.th32ProcessID);
                            //TerminateProcess(process_handle, 2);
                            //CloseHandle(process_handle);
                        }
                    }
                }
                while (Process32Next(snapshot, &process));
            }
            CloseHandle(snapshot);
        }

        // Kill Parent
        HANDLE parent_handle = OpenProcess(
                                  PROCESS_TERMINATE, 
                                  FALSE, 
                                  PARENT_PID);
        TerminateProcess(parent_handle, 2);
        CloseHandle(parent_handle);
    }
}
pico
  • 1,660
  • 4
  • 22
  • 52