1. improved wxKill() implementation for Win32

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
This commit is contained in:
Vadim Zeitlin 2001-06-16 00:59:07 +00:00
parent b3d008dbd5
commit 50567b69d6
9 changed files with 545 additions and 67 deletions

View File

@ -1755,13 +1755,56 @@ this default behaviour.
\membersection{::wxKill}\label{wxkill} \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. Equivalent to the Unix kill function: send the given signal {\it sig} to the
Returns 0 on success, -1 on failure. 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. \begin{verbatim}
It does not raise a signal in the receiving process. 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} \wxheading{Include files}

View 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. If it is NULL, you have not turned on the redirection.
See \helpref{wxProcess::Redirect}{wxprocessredirect}. 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} \membersection{wxProcess::OnTerminate}\label{wxprocessonterminate}
\constfunc{void}{OnTerminate}{\param{int}{ pid}, \param{int}{ status}} \constfunc{void}{OnTerminate}{\param{int}{ pid}, \param{int}{ status}}

View 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). until the program terminates) or asynchronously (notification will come later).
It also shows how to capture the output of the child process in both 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} \subsection{Scroll subwindow sample}\label{samplescrollsub}

View File

@ -16,14 +16,14 @@
#pragma interface "process.h" #pragma interface "process.h"
#endif #endif
#include "wx/defs.h"
#include "wx/object.h"
#include "wx/event.h" #include "wx/event.h"
#if wxUSE_STREAMS #if wxUSE_STREAMS
#include "wx/stream.h" #include "wx/stream.h"
#endif #endif
#include "wx/utils.h" // for wxSignal
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// A wxProcess object should be passed to wxExecute - than its OnTerminate() // A wxProcess object should be passed to wxExecute - than its OnTerminate()
// function will be called when the process terminates. // function will be called when the process terminates.
@ -31,8 +31,6 @@
class WXDLLEXPORT wxProcess : public wxEvtHandler class WXDLLEXPORT wxProcess : public wxEvtHandler
{ {
DECLARE_DYNAMIC_CLASS(wxProcess)
public: public:
wxProcess(wxEvtHandler *parent = (wxEvtHandler *) NULL, int id = -1) wxProcess(wxEvtHandler *parent = (wxEvtHandler *) NULL, int id = -1)
{ Init(parent, id, FALSE); } { Init(parent, id, FALSE); }
@ -69,6 +67,12 @@ public:
wxInputStream *errStream); wxInputStream *errStream);
#endif // wxUSE_STREAMS #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: protected:
void Init(wxEvtHandler *parent, int id, bool redirect); void Init(wxEvtHandler *parent, int id, bool redirect);
@ -81,6 +85,8 @@ protected:
#endif // wxUSE_STREAMS #endif // wxUSE_STREAMS
bool m_redirect; bool m_redirect;
DECLARE_DYNAMIC_CLASS(wxProcess)
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -180,8 +180,22 @@ enum wxSignal
// further signals are different in meaning between different Unix systems // further signals are different in meaning between different Unix systems
}; };
// the argument is ignored under Windows - the process is always killed enum wxKillError
WXDLLEXPORT int wxKill(long pid, wxSignal sig = wxSIGTERM); {
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) // Execute a command in an interactive shell window (always synchronously)
// If no command then just the shell // If no command then just the shell

View File

@ -40,6 +40,7 @@
#include "wx/textdlg.h" #include "wx/textdlg.h"
#include "wx/listbox.h" #include "wx/listbox.h"
#include "wx/filedlg.h" #include "wx/filedlg.h"
#include "wx/choicdlg.h"
#endif #endif
#include "wx/txtstrm.h" #include "wx/txtstrm.h"
@ -83,6 +84,8 @@ public:
// event handlers (these functions should _not_ be virtual) // event handlers (these functions should _not_ be virtual)
void OnQuit(wxCommandEvent& event); void OnQuit(wxCommandEvent& event);
void OnKill(wxCommandEvent& event);
void OnClear(wxCommandEvent& event); void OnClear(wxCommandEvent& event);
void OnSyncExec(wxCommandEvent& event); void OnSyncExec(wxCommandEvent& event);
@ -109,6 +112,9 @@ private:
void DoAsyncExec(const wxString& cmd); void DoAsyncExec(const wxString& cmd);
// the PID of the last process we launched asynchronously
int m_pidLast;
// last command we executed // last command we executed
wxString m_cmdLast; wxString m_cmdLast;
@ -192,6 +198,7 @@ enum
{ {
// menu items // menu items
Exec_Quit = 100, Exec_Quit = 100,
Exec_Kill,
Exec_ClearLog, Exec_ClearLog,
Exec_SyncExec = 200, Exec_SyncExec = 200,
Exec_AsyncExec, 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. // simple menu events like this the static method is much simpler.
BEGIN_EVENT_TABLE(MyFrame, wxFrame) BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Exec_Quit, MyFrame::OnQuit) EVT_MENU(Exec_Quit, MyFrame::OnQuit)
EVT_MENU(Exec_Kill, MyFrame::OnKill)
EVT_MENU(Exec_ClearLog, MyFrame::OnClear) EVT_MENU(Exec_ClearLog, MyFrame::OnClear)
EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec) EVT_MENU(Exec_SyncExec, MyFrame::OnSyncExec)
@ -273,6 +281,8 @@ bool MyApp::OnInit()
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame((wxFrame *)NULL, -1, title, pos, size) : wxFrame((wxFrame *)NULL, -1, title, pos, size)
{ {
m_pidLast = 0;
#ifdef __WXMAC__ #ifdef __WXMAC__
// we need this in order to allow the about menu relocation, since ABOUT is // we need this in order to allow the about menu relocation, since ABOUT is
// not the default id of the about menu // 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 // create a menu bar
wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF); 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"), menuFile->Append(Exec_ClearLog, _T("&Clear log\tCtrl-C"),
_T("Clear the log window")); _T("Clear the log window"));
menuFile->AppendSeparator(); menuFile->AppendSeparator();
@ -334,8 +347,9 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
#endif // wxUSE_STATUSBAR #endif // wxUSE_STATUSBAR
} }
// ----------------------------------------------------------------------------
// event handlers // event handlers: file and help menu
// ----------------------------------------------------------------------------
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{ {
@ -350,15 +364,117 @@ void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
void MyFrame::OnAbout(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); _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) void MyFrame::DoAsyncExec(const wxString& cmd)
{ {
wxProcess *process = new MyProcess(this, cmd); wxProcess *process = new MyProcess(this, cmd);
long pid = wxExecute(cmd, FALSE /* async */, process); m_pidLast = wxExecute(cmd, FALSE /* async */, process);
if ( !pid ) if ( !m_pidLast )
{ {
wxLogError(_T("Execution of '%s' failed."), cmd.c_str()); wxLogError(_T("Execution of '%s' failed."), cmd.c_str());
@ -366,7 +482,7 @@ void MyFrame::DoAsyncExec(const wxString& cmd)
} }
else 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; m_cmdLast = cmd;
} }
@ -543,6 +659,10 @@ void MyFrame::OnFileExec(wxCommandEvent& event)
DoAsyncExec(cmd); DoAsyncExec(cmd);
} }
// ----------------------------------------------------------------------------
// DDE stuff
// ----------------------------------------------------------------------------
#ifdef __WINDOWS__ #ifdef __WINDOWS__
bool MyFrame::GetDDEServer() bool MyFrame::GetDDEServer()
@ -623,6 +743,10 @@ void MyFrame::OnDDERequest(wxCommandEvent& WXUNUSED(event))
#endif // __WINDOWS__ #endif // __WINDOWS__
// ----------------------------------------------------------------------------
// various helpers
// ----------------------------------------------------------------------------
// input polling // input polling
void MyFrame::OnIdle(wxIdleEvent& event) void MyFrame::OnIdle(wxIdleEvent& event)
{ {

View File

@ -9,6 +9,14 @@
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__ #ifdef __GNUG__
#pragma implementation "process.h" #pragma implementation "process.h"
#endif #endif
@ -20,17 +28,25 @@
#pragma hdrstop #pragma hdrstop
#endif #endif
#ifndef WX_PRECOMP
#include "wx/defs.h"
#endif
#include "wx/process.h" #include "wx/process.h"
// ----------------------------------------------------------------------------
// event tables and such
// ----------------------------------------------------------------------------
DEFINE_EVENT_TYPE(wxEVT_END_PROCESS) DEFINE_EVENT_TYPE(wxEVT_END_PROCESS)
IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler) IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler)
IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent) IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent)
// ============================================================================
// wxProcess implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxProcess creation
// ----------------------------------------------------------------------------
void wxProcess::Init(wxEvtHandler *parent, int id, bool redirect) void wxProcess::Init(wxEvtHandler *parent, int id, bool redirect)
{ {
if ( parent ) if ( parent )
@ -46,6 +62,10 @@ void wxProcess::Init(wxEvtHandler *parent, int id, bool redirect)
#endif // wxUSE_STREAMS #endif // wxUSE_STREAMS
} }
// ----------------------------------------------------------------------------
// wxProcess termination
// ----------------------------------------------------------------------------
wxProcess::~wxProcess() wxProcess::~wxProcess()
{ {
#if wxUSE_STREAMS #if wxUSE_STREAMS
@ -70,6 +90,10 @@ void wxProcess::Detach()
SetNextHandler(NULL); SetNextHandler(NULL);
} }
// ----------------------------------------------------------------------------
// process IO redirection
// ----------------------------------------------------------------------------
#if wxUSE_STREAMS #if wxUSE_STREAMS
void wxProcess::SetPipeStreams(wxInputStream *inputSstream, void wxProcess::SetPipeStreams(wxInputStream *inputSstream,
@ -82,3 +106,37 @@ void wxProcess::SetPipeStreams(wxInputStream *inputSstream,
} }
#endif // wxUSE_STREAMS #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;
}
}

View File

@ -513,65 +513,204 @@ bool wxSetEnv(const wxString& var, const wxChar *value)
// process management // process management
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
int wxKill(long pid, wxSignal sig) #ifdef __WIN32__
// structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
struct wxFindByPidParams
{ {
#ifndef __WIN32__ wxFindByPidParams() { hwnd = 0; pid = 0; }
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, // the HWND used to return the result
FALSE, (unsigned long)pid); HWND hwnd;
if (hProcess == NULL)
return -1;
if (sig == wxSIGKILL) // the PID we're looking from
terminateSuccess = (TerminateProcess(hProcess, 0) != 0); DWORD pid;
else if (sig != wxSIGNONE) };
// 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); // remember the window we found
while (hHwnd != 0) 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 )
{ {
unsigned long testpid = 0; *krc = wxKILL_ACCESS_DENIED;
GetWindowThreadProcessId(hHwnd, &testpid); }
if ((unsigned long)pid == testpid) 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 )
{ {
PostMessage(hHwnd, WM_QUIT, 0, 0); // this is not supposed to happen if we could open the
// How to make this better? // process
// If we don't wait, the return value is wrong. *krc = wxKILL_ERROR;
wxSleep(1); }
break;
ok = FALSE;
}
break;
case wxSIGNONE:
// do nothing, we just want to test for process existence
break;
default:
// any other signal means "terminate"
{
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) )
{
// 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
GetExitCodeProcess(hProcess, &code);
CloseHandle(hProcess);
if (sig == wxSIGNONE)
{ {
if (code == STILL_ACTIVE) // just to suppress the warnings about uninitialized variable
return 0; rc = 0;
else
return -1;
} }
else
::CloseHandle(hProcess);
// the return code is the same as from Unix kill(): 0 if killed
// successfully or -1 on error
if ( sig == wxSIGNONE )
{ {
if (!terminateSuccess || code == STILL_ACTIVE) if ( ok && rc == STILL_ACTIVE )
return -1; {
else // there is such process => success
return 0; return 0;
}
} }
#endif else // not SIGNONE
{
if ( ok && rc != STILL_ACTIVE )
{
// killed => success
return 0;
}
}
#else // Win15
wxFAIL_MSG( _T("not implemented") );
#endif // Win32/Win16
// error
return -1;
} }
// Execute a program in an Interactive Shell // Execute a program in an Interactive Shell

View File

@ -135,9 +135,39 @@ void wxUsleep(unsigned long milliseconds)
// process management // 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 #define WXEXECUTE_NARGS 127