Terminate process cleanly[reprint]
I often noticed in the C examples I found on the net, that those examples made use of SafeTerminateProcess so I wondered what this call stands for and why they used it.
After some research I found an article which was from Dr Dobbs written somewhere around 1999 which explains the difficulties around TerminateProcess()
Just to mention a few of them:
Any application that does not have a console control handler or a message loop will not be able to react to the WM_CLOSE and will be killed via TerminateProcess().Deadlock in the message processing thread and using too small a timeout value in the call to WaitForSingleObject(), can cause TerminateProcess() to be used as well.It is generally a bad idea to call TerminateProcess() because the system does not shut down the process in an orderly fashion.Any DLLs used by the process will not receive the DLL_PROCESS_DETACH event, disk buffers are not properly flushed, and memory shared with other processes can be left in an inconsistent state.So what we can do now? Simple make a call to SafeTerminateProcess instead!
safetp.h — Declaration for SafeTerminateProcess()
/* Header file for SafeTerminateProcess */
#ifndef _SAFETP_H__ #define _SAFETP_H__
BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode);
#endif
/* End of File */
SafeTerminateProcess() takes advantage of the fact that Win32′s ExitProcess() has a function signature compatible with that of a thread entry point. By “compatible,” I mean that the parameters of both function prototypes are the same type, but they have different return types. This lets me launch ExitProcess() in any process, using Win32′s CreateRemoteThread(), causing that process to perform an orderly shutdown.
The fact that ExitProcess() has a void return type while a thread function is expected to return a DWORD is not a problem. This just means that the exit code of the remote thread will be whatever happened to be in the return value register (EAX on 80×86 processors) when ExitProcess() finishes.
SafeTerminateProcess() has the same signature as TerminateProcess() and starts out by using DuplicateHandle() to ensure that it will have rights to create a thread in the remote process. Handles returned from CreateProcess() always have full privileges.
SafeTerminateProcess() checks to make sure that the process is still running (no point in shooting a dead horse), and sets an appropriate GetLastError() value if it is not. If it is alive, I call CreateRemoteThread() with ExitProcess() as the entry point and pass SafeTerminateProcess()’s uExitCode parameter as the thread parameter. If the call fails for some reason, SafeTerminateProcess() saves the GetLastError() value so it can use it before returning.
/*
Safely terminate a process by creating a remote thread
in the process that calls ExitProcess
*/
#define STRICT
#include
BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
{
DWORD dwTID, dwCode, dwErr = 0;
HANDLE hProcessDup = INVALID_HANDLE_VALUE;
HANDLE hRT = NULL;
HINSTANCE hKernel = GetModuleHandle("Kernel32");
BOOL bSuccess = FALSE;
BOOL bDup = DuplicateHandle(GetCurrentProcess(),
hProcess,
GetCurrentProcess(),
&hProcessDup,
PROCESS_ALL_ACCESS,
FALSE,
0);
// Detect the special case where the process is
// already dead...
if ( GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
(dwCode == STILL_ACTIVE) )
{
FARPROC pfnExitProc;
pfnExitProc = GetProcAddress(hKernel, "ExitProcess");
hRT = CreateRemoteThread((bDup) ? hProcessDup : hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)pfnExitProc,
(PVOID)uExitCode, 0, &dwTID);
if ( hRT == NULL )
dwErr = GetLastError();
}
else
{
dwErr = ERROR_PROCESS_ABORTED;
}
if ( hRT )
{
// Must wait process to terminate to
// guarantee that it has exited...
WaitForSingleObject((bDup) ? hProcessDup : hProcess,
INFINITE);
CloseHandle(hRT);
bSuccess = TRUE;
}
if ( bDup )
CloseHandle(hProcessDup);
if ( !bSuccess )
SetLastError(dwErr);
return bSuccess;
}
/* End of File */
References
[1] Case with TerminateProcess http://private-storm.de/2009/08/11/case-terminateprocess/
[2] Microsoft Knowledge Base Article #Q178893, HOWTO: Terminate an Application “Cleanly” in Win32,KB Q178893
[3] A Safer Alternative to TerminateProcess() Dr Dobbs