From e0f6b731a80035dab1c2d1224f8a2dea0c9de947 Mon Sep 17 00:00:00 2001
From: Julian Smart <julian@anthemion.co.uk>
Date: Sun, 5 Dec 2004 12:53:25 +0000
Subject: [PATCH] Added flags argument to wxKill and wxProcess::Kill to allow
 it to kill child processes.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@30855 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt           |  1 +
 docs/latex/wx/function.tex | 14 ++++--
 docs/latex/wx/process.tex  |  7 ++-
 include/wx/process.h       |  2 +-
 include/wx/utils.h         | 15 ++++--
 src/common/process.cpp     |  4 +-
 src/mac/carbon/utils.cpp   |  2 +-
 src/mac/classic/utils.cpp  |  2 +-
 src/msw/utils.cpp          | 98 +++++++++++++++++++++++++++++++++++++-
 src/os2/utils.cpp          |  1 +
 src/palmos/utils.cpp       |  3 +-
 src/unix/utilsunx.cpp      |  4 +-
 12 files changed, 134 insertions(+), 19 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index a25f4c9b50..857f4e632c 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -23,6 +23,7 @@ All:
 - use wxStream::GetLength() instead of deprecated GetSize()
 - wxGetOsDescription() is now more precise (Olly Betts)
 - XRC supports system fonts and colours (Ray Gilbert)
+- Added flags argument to wxKill/wxProcess::Kill to kill child processes.
 
 All (GUI):
 
diff --git a/docs/latex/wx/function.tex b/docs/latex/wx/function.tex
index d55c16bb7c..3fce56f13e 100644
--- a/docs/latex/wx/function.tex
+++ b/docs/latex/wx/function.tex
@@ -577,9 +577,9 @@ happening, i.e. with this flag the child process window will be shown normally.
 
 Under Unix the flag {\tt wxEXEC\_MAKE\_GROUP\_LEADER} may be used to ensure
 that the new process is a group leader (this will create a new session if
-needed). Calling \helpref{wxKill}{wxkill} with the argument of -pid where pid
-is the process ID of the new process will kill this process as well as all of
-its children (except those which have started their own session).
+needed). Calling \helpref{wxKill}{wxkill} passing wxKILL\_CHILDREN will
+will kill this process as well as all of its children (except those which have
+started their own session).
 
 Finally, you may use the third overloaded version of this function to execute
 a process (always synchronously) and capture its output in the array
@@ -629,7 +629,7 @@ application. See \helpref{wxCloseEvent}{wxcloseevent} and \helpref{wxApp}{wxapp}
 
 \membersection{::wxKill}\label{wxkill}
 
-\func{int}{wxKill}{\param{long}{ pid}, \param{int}{ sig = wxSIGTERM}, \param{wxKillError }{*rc = NULL}}
+\func{int}{wxKill}{\param{long}{ pid}, \param{int}{ sig = wxSIGTERM}, \param{wxKillError }{*rc = NULL}, \param{int }{flags = 0}}
 
 Equivalent to the Unix kill function: send the given signal {\it sig} to the
 process with PID {\it pid}. The valid signal values are
@@ -674,6 +674,12 @@ enum wxKillError
 };
 \end{verbatim}
 
+The {\it flags} parameter can be wxKILL\_NOCHILDREN (the default),
+or wxKILL\_CHILDREN, in which case the child processes of this
+process will be killed too. Note that under Unix, for wxKILL\_CHILDREN
+to work you should have created the process by passing wxEXEC\_MAKE_GROUP\_LEADER
+to wxExecute.
+
 \wxheading{See also}
 
 \helpref{wxProcess::Kill}{wxprocesskill},\rtfsp
diff --git a/docs/latex/wx/process.tex b/docs/latex/wx/process.tex
index d4dbeec3da..d19b33a4b0 100644
--- a/docs/latex/wx/process.tex
+++ b/docs/latex/wx/process.tex
@@ -155,7 +155,7 @@ Returns {\tt true} if the child process standard output stream is opened.
 
 \membersection{wxProcess::Kill}\label{wxprocesskill}
 
-\func{static wxKillError}{Kill}{\param{int}{ pid}, \param{wxSignal}{ signal = wxSIGNONE}}
+\func{static wxKillError}{Kill}{\param{int}{ pid}, \param{wxSignal}{ signal = wxSIGNONE}, \param{int }{flags = wxKILL\_NOCHILDREN}}
 
 Send the specified signal to the given process. Possible signal values are:
 
@@ -185,6 +185,11 @@ enum wxSignal
 under both Unix and Windows but all the other signals are equivalent to
 {\tt wxSIGTERM} under Windows.
 
+The {\it flags} parameter can be wxKILL\_NOCHILDREN (the default),
+or wxKILL\_CHILDREN, in which case the child processes of this
+process will be killed too. Note that under Unix, for wxKILL\_CHILDREN
+to work you should have created the process passing wxEXEC\_MAKE_GROUP\_LEADER.
+
 Returns the element of {\tt wxKillError} enum:
 
 \begin{verbatim}
diff --git a/include/wx/process.h b/include/wx/process.h
index adefc2620a..fc7049d404 100644
--- a/include/wx/process.h
+++ b/include/wx/process.h
@@ -43,7 +43,7 @@ class WXDLLIMPEXP_BASE wxProcess : public wxEvtHandler
 {
 public:
     // kill the process with the given PID
-    static wxKillError Kill(int pid, wxSignal sig = wxSIGTERM);
+    static wxKillError Kill(int pid, wxSignal sig = wxSIGTERM, int flags = wxKILL_NOCHILDREN);
 
     // test if the given process exists
     static bool Exists(int pid);
diff --git a/include/wx/utils.h b/include/wx/utils.h
index 1cc4f72a8e..a7aba4285c 100644
--- a/include/wx/utils.h
+++ b/include/wx/utils.h
@@ -156,7 +156,7 @@ WXDLLIMPEXP_BASE wxString wxDecToHex(int dec);
 // Process management
 // ----------------------------------------------------------------------------
 
-// NB: for backwars compatibility reasons the values of wxEXEC_[A]SYNC *must*
+// NB: for backwards compatibility reasons the values of wxEXEC_[A]SYNC *must*
 //     be 0 and 1, don't change!
 
 enum
@@ -171,8 +171,8 @@ enum
     // is done by default)
     wxEXEC_NOHIDE   = 2,
 
-    // under Unix, if the process is the group leader then killing -pid kills
-    // all children as well as pid
+    // under Unix, if the process is the group leader then passing wxKILL_CHILDREN to wxKill
+    // kills all children as well as pid
     wxEXEC_MAKE_GROUP_LEADER = 4
 };
 
@@ -228,6 +228,12 @@ enum wxKillError
     wxKILL_ERROR            // another, unspecified error
 };
 
+enum wxKillFlags
+{
+    wxKILL_NOCHILDREN = 0,  // don't kill children
+    wxKILL_CHILDREN = 1     // kill children
+};
+
 enum wxShutdownFlags
 {
     wxSHUTDOWN_POWEROFF,    // power off the computer
@@ -243,7 +249,8 @@ WXDLLIMPEXP_BASE bool wxShutdown(wxShutdownFlags wFlags);
 // return detailed error in rc if not NULL
 WXDLLIMPEXP_BASE int wxKill(long pid,
                        wxSignal sig = wxSIGTERM,
-                       wxKillError *rc = NULL);
+                       wxKillError *rc = NULL,
+                       int flags = wxKILL_NOCHILDREN);
 
 // Execute a command in an interactive shell window (always synchronously)
 // If no command then just the shell
diff --git a/src/common/process.cpp b/src/common/process.cpp
index 4ef1fb157a..3127c762c6 100644
--- a/src/common/process.cpp
+++ b/src/common/process.cpp
@@ -142,10 +142,10 @@ bool wxProcess::IsErrorAvailable() const
 // ----------------------------------------------------------------------------
 
 /* static */
-wxKillError wxProcess::Kill(int pid, wxSignal sig)
+wxKillError wxProcess::Kill(int pid, wxSignal sig, int flags)
 {
     wxKillError rc;
-    (void)wxKill(pid, sig, &rc);
+    (void)wxKill(pid, sig, &rc, flags);
 
     return rc;
 }
diff --git a/src/mac/carbon/utils.cpp b/src/mac/carbon/utils.cpp
index be604f9e30..d61ce0e905 100644
--- a/src/mac/carbon/utils.cpp
+++ b/src/mac/carbon/utils.cpp
@@ -301,7 +301,7 @@ bool wxGetUserName(wxChar *buf, int maxSize)
   return TRUE;
 }
 
-int wxKill(long pid, wxSignal sig , wxKillError *rc )
+int wxKill(long pid, wxSignal sig , wxKillError *rc, int flags)
 {
     // TODO
     return 0;
diff --git a/src/mac/classic/utils.cpp b/src/mac/classic/utils.cpp
index b64f77fae0..09ed7ad31f 100644
--- a/src/mac/classic/utils.cpp
+++ b/src/mac/classic/utils.cpp
@@ -155,7 +155,7 @@ bool wxGetUserName(wxChar *buf, int maxSize)
   return TRUE;
 }
 
-int wxKill(long pid, wxSignal sig , wxKillError *rc )
+int wxKill(long pid, wxSignal sig , wxKillError *rc, int flags)
 {
     // TODO
     return 0;
diff --git a/src/msw/utils.cpp b/src/msw/utils.cpp
index 736a8c90af..9ff3687c46 100644
--- a/src/msw/utils.cpp
+++ b/src/msw/utils.cpp
@@ -94,6 +94,9 @@
     #endif
 #endif
 
+// For wxKillAllChildren
+#include <tlhelp32.h>
+
 // ----------------------------------------------------------------------------
 // constants
 // ----------------------------------------------------------------------------
@@ -649,8 +652,13 @@ BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
     return TRUE;
 }
 
-int wxKill(long pid, wxSignal sig, wxKillError *krc)
+int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
+
+int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags)
 {
+    if (flags & wxKILL_CHILDREN)
+        wxKillAllChildren(pid, sig, krc);
+    
     // get the process handle to operate on
     HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
                                     PROCESS_TERMINATE |
@@ -805,6 +813,94 @@ int wxKill(long pid, wxSignal sig, wxKillError *krc)
     return -1;
 }
 
+HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ;
+BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ;
+BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ;
+  
+static void InitToolHelp32()
+{
+    static bool s_initToolHelpDone = false;
+    
+    if (s_initToolHelpDone)
+        return;
+    
+    s_initToolHelpDone = true;
+
+    lpfCreateToolhelp32Snapshot = NULL;
+    lpfProcess32First = NULL;
+    lpfProcess32Next = NULL;
+    
+    HINSTANCE hInstLib = LoadLibraryA( "Kernel32.DLL" ) ;
+    if( hInstLib == NULL )
+        return ;
+    
+    // Get procedure addresses.
+    // We are linking to these functions of Kernel32
+    // explicitly, because otherwise a module using
+    // this code would fail to load under Windows NT,
+    // which does not have the Toolhelp32
+    // functions in the Kernel 32.
+    lpfCreateToolhelp32Snapshot=
+        (HANDLE(WINAPI *)(DWORD,DWORD))
+        GetProcAddress( hInstLib,
+        "CreateToolhelp32Snapshot" ) ;
+    
+    lpfProcess32First=
+        (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
+        GetProcAddress( hInstLib, "Process32First" ) ;
+
+    lpfProcess32Next=
+        (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
+        GetProcAddress( hInstLib, "Process32Next" ) ;
+
+    FreeLibrary( hInstLib ) ;
+}
+
+// By John Skiff
+int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc)
+{
+    InitToolHelp32();
+    
+    if (krc)
+        *krc = wxKILL_OK;
+    
+    // If not implemented for this platform (e.g. NT 4.0), silently ignore
+    if (!lpfCreateToolhelp32Snapshot || !lpfProcess32First || !lpfProcess32Next)
+        return 0;
+    
+    // Take a snapshot of all processes in the system.
+    HANDLE hProcessSnap = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (hProcessSnap == INVALID_HANDLE_VALUE) {
+        if (krc)
+            *krc = wxKILL_ERROR;
+        return -1;
+    }
+    
+    //Fill in the size of the structure before using it.
+    PROCESSENTRY32 pe = {0};
+    pe.dwSize = sizeof(PROCESSENTRY32);
+    
+    // Walk the snapshot of the processes, and for each process,
+    // kill it if its parent is pid.
+    if (!lpfProcess32First(hProcessSnap, &pe)) {
+        // Can't get first process.
+        if (krc)
+            *krc = wxKILL_ERROR;
+        CloseHandle (hProcessSnap);
+        return -1;
+    }
+    
+    do {
+        if (pe.th32ParentProcessID == (DWORD) pid) {
+            if (wxKill(pe.th32ProcessID, sig, krc))
+                return -1;
+        }
+    } while (lpfProcess32Next (hProcessSnap, &pe));
+    
+    
+    return 0;
+}
+
 // Execute a program in an Interactive Shell
 bool wxShell(const wxString& command)
 {
diff --git a/src/os2/utils.cpp b/src/os2/utils.cpp
index 80f9a04b3c..eb3424d29d 100644
--- a/src/os2/utils.cpp
+++ b/src/os2/utils.cpp
@@ -132,6 +132,7 @@ int wxKill(
   long                              lPid
 , wxSignal                          eSig
 , wxKillError*                      peError
+, int                               flags
 )
 {
     return((int)::DosKillProcess(0, (PID)lPid));
diff --git a/src/palmos/utils.cpp b/src/palmos/utils.cpp
index 67fb7c304b..934ab62e50 100644
--- a/src/palmos/utils.cpp
+++ b/src/palmos/utils.cpp
@@ -126,8 +126,7 @@ bool wxSetEnv(const wxString& var, const wxChar *value)
 // process management
 // ----------------------------------------------------------------------------
 
-// structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
-int wxKill(long pid, wxSignal sig, wxKillError *krc)
+int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags)
 {
     return 0;
 }
diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp
index 927b409122..6115ef3330 100644
--- a/src/unix/utilsunx.cpp
+++ b/src/unix/utilsunx.cpp
@@ -200,9 +200,9 @@ void wxMilliSleep(unsigned long milliseconds)
 // process management
 // ----------------------------------------------------------------------------
 
-int wxKill(long pid, wxSignal sig, wxKillError *rc)
+int wxKill(long pid, wxSignal sig, wxKillError *rc, int flags)
 {
-    int err = kill((pid_t)pid, (int)sig);
+    int err = kill((pid_t) (flags & wxKILL_CHILDREN) ? -pid : pid, (int)sig);
     if ( !err )
        *rc = wxKILL_OK;
     else
-- 
2.50.0

