From: Julian Smart Date: Sun, 5 Dec 2004 12:53:25 +0000 (+0000) Subject: Added flags argument to wxKill and wxProcess::Kill to allow it to X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/e0f6b731a80035dab1c2d1224f8a2dea0c9de947?ds=inline 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 --- 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 + // ---------------------------------------------------------------------------- // 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