How to Effectively Kill a Process in C++ (Win32)

How to effectively kill a process in C++ (Win32)?

The PID you need for OpenProcess() is not normally easy to get a hold of. If all you got is a process name then you need to iterate the running processes on the machine. Do so with CreateToolhelp32Snapshot, followed by Process32First and loop with Process32Next. The PROCESSENTRY32.szExeFile gives you the process name (not path!), th32ProcessID gives you the PID.

The next consideration is that the process may appear more than once. And there's a chance that the same process name is used for very different programs. Like "Setup". If you don't just want to kill them all, you'll need to try to obtain some runtime info from them. Window caption bar text, perhaps. GetProcessImageFileName() can give you the path to the .exe. It uses the native kernel format, you'd need QueryDosDevice to map a disk drive device name to a drive letter.

The next consideration is the rights you ask for in OpenProcess(). You are unlikely to get PROCESS_ALL_ACCESS, all you need is PROCESS_TERMINATE. Although that's privileged as well. Ensure the account you use to run your program can obtain that right.

Killing a windows process efficiently

Efficiency and performance should not worry you, IMO. You're probably not going to kill 1000 processes a second, so if one takes 10ms and the other takes 100ms, I doubt anyone will care.

So, the arguments for choosing one of the other is mostly ease of programming and maintaining. The API for enumerating processes is not the easiest, but you can find many example on the web (like here). Using tasklist will require obtaining the output and parsing it.

I'd go for the API for these reasons:

  1. You can get more information in case the operation fails. You'll know exactly where the problem was, and what was it.
  2. I'm not sure tasklist and taskkill are guaranteed to be on every Windows machine. They do come with the OS, but someone might figure they enlarge the attack surface or whatever, and remove them.
  3. Parsing text is error prone. I have no idea, for instance, if tasklist's output depends on the OS locale. Do you?

Way to kill a process programmatically by PID

Fortunately, killing it once you have a PID is pretty easy.

  1. do OpenProcess to get a process handle from the PID

    • be sure to specify the PROCESS_TERMINATE right.
  2. do TerminateProcess to kill the process

Terminate a process tree (C for Windows)

Check this thread for grouping processes within a "job".

If that does not work for you, a home grown approach might go as follows:

  1. Get your main process ID
  2. Call CreateToolhelp32Snapshot to enumerateall the processes on the system
  3. Check the th32ParentProcessID member of the PROCESSENTRY32 structure on each process, if it matches your parent ID, then terminate the process (using TerminateProcess)
  4. After all children are terminated, terminate the main process

Sample code:

    DWORD myprocID = 1234; // your main process id

PROCESSENTRY32 pe;

memset(&pe, 0, sizeof(PROCESSENTRY32));
pe.dwSize = sizeof(PROCESSENTRY32);

HANDLE hSnap = :: CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if (::Process32First(hSnap, &pe))
{
BOOL bContinue = TRUE;

// kill child processes
while (bContinue)
{
// only kill child processes
if (pe.th32ParentProcessID == myprocID)
{
HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);

if (hChildProc)
{
::TerminateProcess(hChildProc, 1);
::CloseHandle(hChildProc);
}
}

bContinue = ::Process32Next(hSnap, &pe);
}

// kill the main process
HANDLE hProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, myprocID);

if (hProc)
{
::TerminateProcess(hProc, 1);
::CloseHandle(hProc);
}
}

Kill child process with cleanup

If you are on windows, you probably start your child processes by CreateProcess, which has a PROCESS_INFORMATION as the last parameter.

CreateProcess on MSDN

Process Information on MSDN

Option 1:

This process information contains a handle to the process started in the hProcess member.

You can store this handle and use it to kill your child processes.

Insert
You probably want to send WM_CLOSE and / or WM_QUIT?
to "cleanly" end the process:

Here is a KB Article on what to do KB how to cleanly kill win32 processes

** End Insert**

Option 2:

Here is an discussion on how to properly kill a process tree: Terminate a process tree on windows

how to terminate a process created by CreateProcess()?

In the struct pi you get:

typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;

The first parameter is the handle to the process.

You can use that handle to end the process:

BOOL WINAPI TerminateProcess(
__in HANDLE hProcess,
__in UINT uExitCode
);

hProcess [in]
A handle to the process to be terminated.

The handle must have the PROCESS_TERMINATE access right. For more information, see Process Security and Access Rights.

uExitCode [in]
The exit code to be used by the process and threads terminated as a result of this call. Use the GetExitCodeProcess function to retrieve a process's exit value. Use the GetExitCodeThread function to retrieve a thread's exit value.

Performing equivalent of Kill Process Tree in C++ on windows

You might want to consider the "Jobs API". CreateJobObject and friends. You can enforce children processes to stay within the Job, by setting appropriate attribute. Then you can call TerminateJobObject whenever you want.

Clarification: this is NOT what Task Manager does.

How to gracefully terminate a process?

EnumWindows enumerates all the top level windows in a process. GetWindowThreadProcessId gets the process and Id of each thread.

You now have enough information to gracefully close any GUI application.

You can send WM_CLOSE messages to any window you wish to close. Many windows handle WM_CLOSE to prompt the user to save documents.You can send a WM_QUIT message using PostThreadMessage to the discovered threads to cause the message loop to terminate.

User code is not allowed to call DestroyWindow from a different app or thread to the windows... if the app does not respond to WM_CLOSE or WM_QUIT requests you're back in TerminateProcess land.

This will not close console applications as the application process, and process that owns the window, are different.


Refer to T.s. Arun's answer below for the correct method for dealing with console applications.



Related Topics



Leave a reply



Submit