]> git.saurik.com Git - wxWidgets.git/commitdiff
1. improved wxKill() implementation for Win32
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 16 Jun 2001 00:59:07 +0000 (00:59 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 16 Jun 2001 00:59:07 +0000 (00:59 +0000)
2. added wxKillError output parameter to wxKill
3. added wxProcess::Kill() and Exists()
4. documented all the new stuff
5. updated the sample to show it

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@10592 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/latex/wx/function.tex
docs/latex/wx/process.tex
docs/latex/wx/tsamples.tex
include/wx/process.h
include/wx/utils.h
samples/exec/exec.cpp
src/common/process.cpp
src/msw/utils.cpp
src/unix/utilsunx.cpp

index 1bbd53512e8ad34765501eaa10235a052ecac95a..e35b960e45c64625e7bbc70bbe203dd86ce069ed 100644 (file)
@@ -1755,13 +1755,56 @@ this default behaviour.
 
 \membersection{::wxKill}\label{wxkill}
 
-\func{int}{wxKill}{\param{long}{ pid}, \param{int}{ sig}}
+\func{int}{wxKill}{\param{long}{ pid}, \param{int}{ sig = wxSIGTERM}, \param{wxKillError }{*rc = NULL}}
 
-Under Unix (the only supported platform), equivalent to the Unix kill function.
-Returns 0 on success, -1 on failure.
+Equivalent to the Unix kill function: send the given signal {\it sig} to the
+process with PID {\it pid}. The valud signal values are
 
-Tip: sending a signal of 0 to a process returns -1 if the process does not exist.
-It does not raise a signal in the receiving process.
+\begin{verbatim}
+enum wxSignal
+{
+    wxSIGNONE = 0,  // verify if the process exists under Unix
+    wxSIGHUP,
+    wxSIGINT,
+    wxSIGQUIT,
+    wxSIGILL,
+    wxSIGTRAP,
+    wxSIGABRT,
+    wxSIGEMT,
+    wxSIGFPE,
+    wxSIGKILL,      // forcefully kill, dangerous!
+    wxSIGBUS,
+    wxSIGSEGV,
+    wxSIGSYS,
+    wxSIGPIPE,
+    wxSIGALRM,
+    wxSIGTERM       // terminate the process gently
+};
+\end{verbatim}
+
+{\tt wxSIGNONE}, {\tt wxSIGKILL} and {\tt wxSIGTERM} have the same meaning
+under both Unix and Windows but all the other signals are equivalent to 
+{\tt wxSIGTERM} under Windows.
+
+Returns 0 on success, -1 on failure. If {\it rc} parameter is not NULL, it will
+be filled with an element of {\tt wxKillError} enum:
+
+\begin{verbatim}
+enum wxKillError
+{
+    wxKILL_OK,              // no error
+    wxKILL_BAD_SIGNAL,      // no such signal
+    wxKILL_ACCESS_DENIED,   // permission denied
+    wxKILL_NO_PROCESS,      // no such process
+    wxKILL_ERROR            // another, unspecified error
+};
+\end{verbatim}
+
+\wxheading{See also}
+
+\helpref{wxProcess::Kill}{wxprocesskill},\rtfsp
+\helpref{wxProcess::Exists}{wxprocessexists},\rtfsp
+\helpref{Exec sample}{sampleexex}
 
 \wxheading{Include files}
 
index 425930487f78f58e74c892f360ebe113af8292a2..4f7777e6ebfb6d25d4da6299b9ee07b58836bcfb 100644 (file)
@@ -108,6 +108,68 @@ It returns an output stream correspoding to the input stream of the subprocess.
 If it is NULL, you have not turned on the redirection.
 See \helpref{wxProcess::Redirect}{wxprocessredirect}.
 
+\membersection{wxProcess::Kill}\label{wxprocesskill}
+
+\func{static wxKillError}{Kill}{\param{int}{ pid}, \param{wxSignal}{ signal = wxSIGNONE}}
+
+Send the specified signal to the given process. Possible signal values are:
+
+\begin{verbatim}
+enum wxSignal
+{
+    wxSIGNONE = 0,  // verify if the process exists under Unix
+    wxSIGHUP,
+    wxSIGINT,
+    wxSIGQUIT,
+    wxSIGILL,
+    wxSIGTRAP,
+    wxSIGABRT,
+    wxSIGEMT,
+    wxSIGFPE,
+    wxSIGKILL,      // forcefully kill, dangerous!
+    wxSIGBUS,
+    wxSIGSEGV,
+    wxSIGSYS,
+    wxSIGPIPE,
+    wxSIGALRM,
+    wxSIGTERM       // terminate the process gently
+};
+\end{verbatim}
+
+{\tt wxSIGNONE}, {\tt wxSIGKILL} and {\tt wxSIGTERM} have the same meaning
+under both Unix and Windows but all the other signals are equivalent to 
+{\tt wxSIGTERM} under Windows.
+
+Returns the element of {\tt wxKillError} enum:
+
+\begin{verbatim}
+enum wxKillError
+{
+    wxKILL_OK,              // no error
+    wxKILL_BAD_SIGNAL,      // no such signal
+    wxKILL_ACCESS_DENIED,   // permission denied
+    wxKILL_NO_PROCESS,      // no such process
+    wxKILL_ERROR            // another, unspecified error
+};
+\end{verbatim}
+
+\wxheading{See also}
+
+\helpref{wxProcess::Exists}{wxprocessexists},\rtfsp
+\helpref{wxKill}{wxkill},\rtfsp
+\helpref{Exec sample}{sampleexex}
+
+\membersection{wxProcess::Kill}\label{wxprocessexists}
+
+\func{static bool}{Exists}{\param{int}{ pid}}
+
+Returns {\tt TRUE} if the given process exists in the system.
+
+\wxheading{See also}
+
+\helpref{wxProcess::Kill}{wxprocesskill},\rtfsp
+\helpref{Exec sample}{sampleexex}
+
 \membersection{wxProcess::OnTerminate}\label{wxprocessonterminate}
 
 \constfunc{void}{OnTerminate}{\param{int}{ pid}, \param{int}{ status}}
index a476c6c1a173ba906f1cabdffd4d84f02e5b37b9..9bc339c8a71ddd1be2ed5ff1fc0db4796cd59af1 100644 (file)
@@ -162,7 +162,9 @@ external programs and the sample shows how to do this synchronously (waiting
 until the program terminates) or asynchronously (notification will come later).
 
 It also shows how to capture the output of the child process in both
-synchronous and asynchronous cases.
+synchronous and asynchronous cases and how to kill the processes with 
+\helpref{wxProcess::Kill}{wxprocesskill} and test for their existence with 
+\helpref{wxProcess::Exists}{wxprocessexists}.
 
 \subsection{Scroll subwindow sample}\label{samplescrollsub}
 
index ddf87b3a0409fdd2a9a527ee16645301fee4e95e..571bf65c2947e9762eb535e852ebe50b30c33707 100644 (file)
     #pragma interface "process.h"
 #endif
 
-#include "wx/defs.h"
-#include "wx/object.h"
 #include "wx/event.h"
 
 #if wxUSE_STREAMS
     #include "wx/stream.h"
 #endif
 
+#include "wx/utils.h"       // for wxSignal
+
 // ----------------------------------------------------------------------------
 // A wxProcess object should be passed to wxExecute - than its OnTerminate()
 // function will be called when the process terminates.
@@ -31,8 +31,6 @@
 
 class WXDLLEXPORT wxProcess : public wxEvtHandler
 {
-DECLARE_DYNAMIC_CLASS(wxProcess)
-
 public:
     wxProcess(wxEvtHandler *parent = (wxEvtHandler *) NULL, int id = -1)
         { Init(parent, id, FALSE); }
@@ -69,6 +67,12 @@ public:
                         wxInputStream *errStream);
 #endif // wxUSE_STREAMS
 
+    // kill the process with the given PID
+    static wxKillError Kill(int pid, wxSignal sig = wxSIGTERM);
+
+    // test if the given process exists
+    static bool Exists(int pid);
+
 protected:
     void Init(wxEvtHandler *parent, int id, bool redirect);
 
@@ -81,6 +85,8 @@ protected:
 #endif // wxUSE_STREAMS
 
     bool m_redirect;
+
+    DECLARE_DYNAMIC_CLASS(wxProcess)
 };
 
 // ----------------------------------------------------------------------------
index 4c834988903c44bcaa190cf2d43df57862947a70..519c5ada1a5e4cf8abc0ad005c74ffa8f7c0e29e 100644 (file)
@@ -180,8 +180,22 @@ enum wxSignal
     // further signals are different in meaning between different Unix systems
 };
 
-// the argument is ignored under Windows - the process is always killed
-WXDLLEXPORT int wxKill(long pid, wxSignal sig = wxSIGTERM);
+enum wxKillError
+{
+    wxKILL_OK,              // no error
+    wxKILL_BAD_SIGNAL,      // no such signal
+    wxKILL_ACCESS_DENIED,   // permission denied
+    wxKILL_NO_PROCESS,      // no such process
+    wxKILL_ERROR            // another, unspecified error
+};
+
+// send the given signal to the process (only NONE and KILL are supported under
+// Windows, all others mean TERM), return 0 if ok and -1 on error
+//
+// return detailed error in rc if not NULL
+WXDLLEXPORT int wxKill(long pid,
+                       wxSignal sig = wxSIGTERM,
+                       wxKillError *rc = NULL);
 
 // Execute a command in an interactive shell window (always synchronously)
 // If no command then just the shell
index 80f4f4335d938ced49c1bab13b28763a98cc3845..1634f47fb7bbc1243dcd36663204bad2ef59755b 100644 (file)
@@ -40,6 +40,7 @@
     #include "wx/textdlg.h"
     #include "wx/listbox.h"
     #include "wx/filedlg.h"
+    #include "wx/choicdlg.h"
 #endif
 
 #include "wx/txtstrm.h"
@@ -83,6 +84,8 @@ public:
     // event handlers (these functions should _not_ be virtual)
     void OnQuit(wxCommandEvent& event);
 
+    void OnKill(wxCommandEvent& event);
+
     void OnClear(wxCommandEvent& event);
 
     void OnSyncExec(wxCommandEvent& event);
@@ -109,6 +112,9 @@ private:
 
     void DoAsyncExec(const wxString& cmd);
 
+    // the PID of the last process we launched asynchronously
+    int m_pidLast;
+
     // last command we executed
     wxString m_cmdLast;
 
@@ -192,6 +198,7 @@ enum
 {
     // menu items
     Exec_Quit = 100,
+    Exec_Kill,
     Exec_ClearLog,
     Exec_SyncExec = 200,
     Exec_AsyncExec,
@@ -215,6 +222,7 @@ static const wxChar *DIALOG_TITLE = _T("Exec sample");
 // simple menu events like this the static method is much simpler.
 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(Exec_Quit,  MyFrame::OnQuit)
+    EVT_MENU(Exec_Kill,  MyFrame::OnKill)
     EVT_MENU(Exec_ClearLog,  MyFrame::OnClear)
 
     EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec)
@@ -273,6 +281,8 @@ bool MyApp::OnInit()
 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
        : wxFrame((wxFrame *)NULL, -1, title, pos, size)
 {
+    m_pidLast = 0;
+
 #ifdef __WXMAC__
     // we need this in order to allow the about menu relocation, since ABOUT is
     // not the default id of the about menu
@@ -281,6 +291,9 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
 
     // create a menu bar
     wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF);
+    menuFile->Append(Exec_Kill, _T("&Kill process...\tCtrl-K"),
+                     _T("Kill a process by PID"));
+    menuFile->AppendSeparator();
     menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"),
                      _T("Clear the log window"));
     menuFile->AppendSeparator();
@@ -334,8 +347,9 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
 #endif // wxUSE_STATUSBAR
 }
 
-
-// event handlers
+// ----------------------------------------------------------------------------
+// event handlers: file and help menu
+// ----------------------------------------------------------------------------
 
 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 {
@@ -350,15 +364,117 @@ void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
 
 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
 {
-    wxMessageBox(_T("Exec sample\n© 2000 Vadim Zeitlin"),
+    wxMessageBox(_T("Exec wxWindows Sample\n© 2000-2001 Vadim Zeitlin"),
                  _T("About Exec"), wxOK | wxICON_INFORMATION, this);
 }
 
+void MyFrame::OnKill(wxCommandEvent& WXUNUSED(event))
+{
+    long pid = wxGetNumberFromUser(_T("Please specify the process to kill"),
+                                   _T("Enter PID:"),
+                                   _T("Exec question"),
+                                   m_pidLast,
+                                   1, INT_MAX,
+                                   this);
+    if ( pid == -1 )
+    {
+        // cancelled
+        return;
+    }
+
+    static const wxString signalNames[] =
+    {
+        _T("Just test (SIGNONE)"),
+        _T("Hangup (SIGHUP)"),
+        _T("Interrupt (SIGINT)"),
+        _T("Quit (SIGQUIT)"),
+        _T("Illegal instruction (SIGILL)"),
+        _T("Trap (SIGTRAP)"),
+        _T("Abort (SIGABRT)"),
+        _T("Emulated trap (SIGEMT)"),
+        _T("FP exception (SIGFPE)"),
+        _T("Kill (SIGKILL)"),
+        _T("Bus (SIGBUS)"),
+        _T("Segment violation (SIGSEGV)"),
+        _T("System (SIGSYS)"),
+        _T("Broken pipe (SIGPIPE)"),
+        _T("Alarm (SIGALRM)"),
+        _T("Terminate (SIGTERM)"),
+    };
+
+    int sig = wxGetSingleChoiceIndex(_T("How to kill the process?"),
+                                     _T("Exec question"),
+                                     WXSIZEOF(signalNames), signalNames,
+                                     this);
+    switch ( sig )
+    {
+        default:
+            wxFAIL_MSG( _T("unexpected return value") );
+            // fall through
+
+        case -1:
+            // cancelled
+            return;
+
+        case wxSIGNONE:
+        case wxSIGHUP:
+        case wxSIGINT:
+        case wxSIGQUIT:
+        case wxSIGILL:
+        case wxSIGTRAP:
+        case wxSIGABRT:
+        case wxSIGEMT:
+        case wxSIGFPE:
+        case wxSIGKILL:
+        case wxSIGBUS:
+        case wxSIGSEGV:
+        case wxSIGSYS:
+        case wxSIGPIPE:
+        case wxSIGALRM:
+        case wxSIGTERM:
+            break;
+    }
+
+    if ( sig == 0 )
+    {
+        if ( wxProcess::Exists(pid) )
+            wxLogStatus(_T("Process %d is running."), pid);
+        else
+            wxLogStatus(_T("No process with pid = %d."), pid);
+    }
+    else // not SIGNONE
+    {
+        wxKillError rc = wxProcess::Kill(pid, (wxSignal)sig);
+        if ( rc == wxKILL_OK )
+        {
+            wxLogStatus(_T("Process %d killed with signal %d."), pid, sig);
+        }
+        else
+        {
+            static const wxChar *errorText[] =
+            {
+                _T(""), // no error
+                _T("signal not supported"),
+                _T("permission denied"),
+                _T("no such process"),
+                _T("unspecified error"),
+            };
+
+            wxLogStatus(_T("Failed to kill process %d with signal %d: %s"),
+                        pid, sig, errorText[rc]);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// event handlers: exec menu
+// ----------------------------------------------------------------------------
+
 void MyFrame::DoAsyncExec(const wxString& cmd)
 {
     wxProcess *process = new MyProcess(this, cmd);
-    long pid = wxExecute(cmd, FALSE /* async */, process);
-    if ( !pid )
+    m_pidLast = wxExecute(cmd, FALSE /* async */, process);
+    if ( !m_pidLast )
     {
         wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
 
@@ -366,7 +482,7 @@ void MyFrame::DoAsyncExec(const wxString& cmd)
     }
     else
     {
-        wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str());
+        wxLogStatus(_T("Process %ld (%s) launched."), m_pidLast, cmd.c_str());
 
         m_cmdLast = cmd;
     }
@@ -543,6 +659,10 @@ void MyFrame::OnFileExec(wxCommandEvent& event)
     DoAsyncExec(cmd);
 }
 
+// ----------------------------------------------------------------------------
+// DDE stuff
+// ----------------------------------------------------------------------------
+
 #ifdef __WINDOWS__
 
 bool MyFrame::GetDDEServer()
@@ -623,6 +743,10 @@ void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event))
 
 #endif // __WINDOWS__
 
+// ----------------------------------------------------------------------------
+// various helpers
+// ----------------------------------------------------------------------------
+
 // input polling
 void MyFrame::OnIdle(wxIdleEvent& event)
 {
index 7d9cdbec7294fcbf678d091d73aac4c2e7a15168..e57f66688bc3c0d3e8a3dd9c06a342a569dbfa87 100644 (file)
@@ -9,6 +9,14 @@
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
 #ifdef __GNUG__
     #pragma implementation "process.h"
 #endif
     #pragma hdrstop
 #endif
 
-#ifndef WX_PRECOMP
-    #include "wx/defs.h"
-#endif
-
 #include "wx/process.h"
 
+// ----------------------------------------------------------------------------
+// event tables and such
+// ----------------------------------------------------------------------------
+
 DEFINE_EVENT_TYPE(wxEVT_END_PROCESS)
 
 IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler)
 IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent)
 
+// ============================================================================
+// wxProcess implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxProcess creation
+// ----------------------------------------------------------------------------
+
 void wxProcess::Init(wxEvtHandler *parent, int id, bool redirect)
 {
     if ( parent )
@@ -46,6 +62,10 @@ void wxProcess::Init(wxEvtHandler *parent, int id, bool redirect)
 #endif // wxUSE_STREAMS
 }
 
+// ----------------------------------------------------------------------------
+// wxProcess termination
+// ----------------------------------------------------------------------------
+
 wxProcess::~wxProcess()
 {
 #if wxUSE_STREAMS
@@ -70,6 +90,10 @@ void wxProcess::Detach()
     SetNextHandler(NULL);
 }
 
+// ----------------------------------------------------------------------------
+// process IO redirection
+// ----------------------------------------------------------------------------
+
 #if wxUSE_STREAMS
 
 void wxProcess::SetPipeStreams(wxInputStream *inputSstream,
@@ -82,3 +106,37 @@ void wxProcess::SetPipeStreams(wxInputStream *inputSstream,
 }
 
 #endif // wxUSE_STREAMS
+
+// ----------------------------------------------------------------------------
+// process killing
+// ----------------------------------------------------------------------------
+
+/* static */
+wxKillError wxProcess::Kill(int pid, wxSignal sig)
+{
+    wxKillError rc;
+    (void)wxKill(pid, sig, &rc);
+
+    return rc;
+}
+
+/* static */
+bool wxProcess::Exists(int pid)
+{
+    switch ( wxProcess::Kill(pid, wxSIGNONE) )
+    {
+        case wxKILL_OK:
+        case wxKILL_ACCESS_DENIED:
+            return TRUE;
+
+        default:
+        case wxKILL_ERROR:
+        case wxKILL_BAD_SIGNAL:
+            wxFAIL_MSG( _T("unexpected wxProcess::Kill() return code") );
+            // fall through
+
+        case wxKILL_NO_PROCESS:
+            return FALSE;
+    }
+}
+
index 215806852d1d0068461224052b17932990e1d934..f5efb921f00893465a43df83d82b88b80dfbd423 100644 (file)
@@ -513,65 +513,204 @@ bool wxSetEnv(const wxString& var, const wxChar *value)
 // process management
 // ----------------------------------------------------------------------------
 
-int wxKill(long pid, wxSignal sig)
+#ifdef __WIN32__
+
+// structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
+struct wxFindByPidParams
 {
-#ifndef __WIN32__
-    return -1;
-#else
-    // This in a work in progress. We need to eliminate the call to wxSleep,
-    // deal with child processes, and also test it :-)
-    HWND hHwnd;
-    HANDLE hProcess;
-    unsigned long code;
-    bool terminateSuccess = TRUE;
-
-    hProcess = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
-                           FALSE, (unsigned long)pid);
-    if (hProcess == NULL)
-        return -1;
+    wxFindByPidParams() { hwnd = 0; pid = 0; }
+
+    // the HWND used to return the result
+    HWND hwnd;
 
-    if (sig == wxSIGKILL)
-        terminateSuccess = (TerminateProcess(hProcess, 0) != 0);
-    else if (sig != wxSIGNONE)
+    // the PID we're looking from
+    DWORD pid;
+};
+
+// wxKill helper: EnumWindows() callback which is used to find the first (top
+// level) window belonging to the given process
+BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
+{
+    DWORD pid;
+    (void)::GetWindowThreadProcessId(hwnd, &pid);
+
+    wxFindByPidParams *params = (wxFindByPidParams *)lParam;
+    if ( pid == params->pid )
     {
-        hHwnd = ::FindWindow(NULL, NULL);
-        while (hHwnd != 0)
+        // remember the window we found
+        params->hwnd = hwnd;
+
+        // return FALSE to stop the enumeration
+        return FALSE;
+    }
+
+    // continue enumeration
+    return TRUE;
+}
+
+#endif // __WIN32__
+
+int wxKill(long pid, wxSignal sig, wxKillError *krc)
+{
+#ifdef __WIN32__
+    // get the process handle to operate on
+    HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
+                                    PROCESS_TERMINATE |
+                                    PROCESS_QUERY_INFORMATION,
+                                    FALSE, // not inheritable
+                                    (DWORD)pid);
+    if ( hProcess == NULL )
+    {
+        if ( krc )
         {
-            if (::GetParent(hHwnd) == 0)
+            if ( ::GetLastError() == ERROR_ACCESS_DENIED )
+            {
+                *krc = wxKILL_ACCESS_DENIED;
+            }
+            else
+            {
+                *krc = wxKILL_NO_PROCESS;
+            }
+        }
+
+        return -1;
+    }
+
+    bool ok = TRUE;
+    switch ( sig )
+    {
+        case wxSIGKILL:
+            // kill the process forcefully returning -1 as error code
+            if ( !::TerminateProcess(hProcess, (UINT)-1) )
+            {
+                wxLogSysError(_("Failed to kill process %d"), pid);
+
+                if ( krc )
+                {
+                    // this is not supposed to happen if we could open the
+                    // process
+                    *krc = wxKILL_ERROR;
+                }
+
+                ok = FALSE;
+            }
+            break;
+
+        case wxSIGNONE:
+            // do nothing, we just want to test for process existence
+            break;
+
+        default:
+            // any other signal means "terminate"
             {
-                unsigned long testpid = 0;
-                GetWindowThreadProcessId(hHwnd, &testpid);
-                if ((unsigned long)pid == testpid)
+                wxFindByPidParams params;
+                params.pid = (DWORD)pid;
+
+                // EnumWindows() has nice semantics: it returns 0 if it found
+                // something or if an error occured and non zero if it
+                // enumerated all the window
+                if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)&params) )
                 {
-                    PostMessage(hHwnd, WM_QUIT, 0, 0);
-                    // How to make this better?
-                    // If we don't wait, the return value is wrong.
-                    wxSleep(1);
-                    break;
+                    // did we find any window?
+                    if ( params.hwnd )
+                    {
+                        // tell the app to close
+                        //
+                        // NB: this is the harshest way, the app won't have
+                        //     opportunity to save any files, for example, but
+                        //     this is probably what we want here. If not we
+                        //     can also use SendMesageTimeout(WM_CLOSE)
+                        if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) )
+                        {
+                            wxLogLastError(_T("PostMessage(WM_QUIT)"));
+                        }
+                    }
+                    else // it was an error then
+                    {
+                        wxLogLastError(_T("EnumWindows"));
+
+                        ok = FALSE;
+                    }
+                }
+                else // no windows for this PID
+                {
+                    if ( krc )
+                    {
+                        *krc = wxKILL_ERROR;
+                    }
+
+                    ok = FALSE;
                 }
             }
-            hHwnd = GetWindow(hHwnd, GW_HWNDNEXT);
+    }
+
+    // the return code
+    DWORD rc;
+
+    if ( ok )
+    {
+        // as we wait for a short time, we can use just WaitForSingleObject()
+        // and not MsgWaitForMultipleObjects()
+        switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) )
+        {
+            case WAIT_OBJECT_0:
+                // process terminated
+                if ( !::GetExitCodeProcess(hProcess, &rc) )
+                {
+                    wxLogLastError(_T("GetExitCodeProcess"));
+                }
+                break;
+
+            default:
+                wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") );
+                // fall through
+
+            case WAIT_FAILED:
+                wxLogLastError(_T("WaitForSingleObject"));
+                // fall through
+
+            case WAIT_TIMEOUT:
+                if ( krc )
+                {
+                    *krc = wxKILL_ERROR;
+                }
+
+                rc = STILL_ACTIVE;
+                break;
         }
     }
+    else // !ok
+    {
+        // just to suppress the warnings about uninitialized variable
+        rc = 0;
+    }
 
-    GetExitCodeProcess(hProcess, &code);
-    CloseHandle(hProcess);
+    ::CloseHandle(hProcess);
 
-    if (sig == wxSIGNONE)
+    // the return code is the same as from Unix kill(): 0 if killed
+    // successfully or -1 on error
+    if ( sig == wxSIGNONE )
     {
-        if (code == STILL_ACTIVE)
+        if ( ok && rc == STILL_ACTIVE )
+        {
+            // there is such process => success
             return 0;
-        else
-            return -1;
+        }
     }
-    else
+    else // not SIGNONE
     {
-        if (!terminateSuccess || code == STILL_ACTIVE)
-            return -1;
-        else
+        if ( ok && rc != STILL_ACTIVE )
+        {
+            // killed => success
             return 0;
+        }
     }
-#endif
+#else // Win15
+    wxFAIL_MSG( _T("not implemented") );
+#endif // Win32/Win16
+
+    // error
+    return -1;
 }
 
 // Execute a program in an Interactive Shell
index deeaa836bab486d1308dd1ef5077855bae05969f..23658ace65510ea4c523412dab259f6b4960474e 100644 (file)
@@ -135,9 +135,39 @@ void wxUsleep(unsigned long milliseconds)
 // process management
 // ----------------------------------------------------------------------------
 
-int wxKill(long pid, wxSignal sig)
+int wxKill(long pid, wxSignal sig, wxKillError *rc)
 {
-    return kill((pid_t)pid, (int)sig);
+    int err = kill((pid_t)pid, (int)sig);
+    if ( rc )
+    {
+        switch ( err )
+        {
+            case 0:
+                *rc = wxKILL_OK;
+                break;
+
+            case EINVAL:
+                *rc = wxKILL_BAD_SIGNAL;
+                break;
+
+            case EPERM:
+                *rc = wxKILL_ACCESS_DENIED;
+                break;
+
+            case ESRCH:
+                *rc = wxKILL_NO_PROCESS;
+                break;
+
+            default:
+                // this goes against Unix98 docs so log it
+                wxLogDebug(_T("unexpected kill(2) return value %d"), err);
+
+                // something else...
+                *rc = wxKILL_ERROR;
+        }
+    }
+
+    return err;
 }
 
 #define WXEXECUTE_NARGS   127