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:
parent
b3d008dbd5
commit
50567b69d6
@ -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}
|
||||
|
||||
|
@ -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}}
|
||||
|
@ -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}
|
||||
|
||||
|
@ -16,14 +16,14 @@
|
||||
#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)
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -9,6 +9,14 @@
|
||||
// Licence: wxWindows license
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef __GNUG__
|
||||
#pragma implementation "process.h"
|
||||
#endif
|
||||
@ -20,17 +28,25 @@
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
wxFindByPidParams() { hwnd = 0; pid = 0; }
|
||||
|
||||
hProcess = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
|
||||
FALSE, (unsigned long)pid);
|
||||
if (hProcess == NULL)
|
||||
return -1;
|
||||
// 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 )
|
||||
{
|
||||
unsigned long testpid = 0;
|
||||
GetWindowThreadProcessId(hHwnd, &testpid);
|
||||
if ((unsigned long)pid == testpid)
|
||||
*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 )
|
||||
{
|
||||
PostMessage(hHwnd, WM_QUIT, 0, 0);
|
||||
// How to make this better?
|
||||
// If we don't wait, the return value is wrong.
|
||||
wxSleep(1);
|
||||
break;
|
||||
// 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"
|
||||
{
|
||||
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)¶ms) )
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
GetExitCodeProcess(hProcess, &code);
|
||||
CloseHandle(hProcess);
|
||||
|
||||
if (sig == wxSIGNONE)
|
||||
else // !ok
|
||||
{
|
||||
if (code == STILL_ACTIVE)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
// just to suppress the warnings about uninitialized variable
|
||||
rc = 0;
|
||||
}
|
||||
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)
|
||||
return -1;
|
||||
else
|
||||
if ( ok && rc == STILL_ACTIVE )
|
||||
{
|
||||
// there is such process => success
|
||||
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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user