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}
|
\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}
|
||||||
|
|
||||||
|
@ -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}}
|
||||||
|
@ -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}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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)¶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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user