wxProcess fixes (Detach() added), cleared/corrected wxExecute() documentation

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1709 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1999-02-17 17:56:59 +00:00
parent ca5c8b2df6
commit 7e84f02dfd
6 changed files with 149 additions and 100 deletions

View File

@@ -946,11 +946,12 @@ arguments, terminated by NULL.
If {\it sync} is FALSE (the default), flow of control immediately returns. If {\it sync} is FALSE (the default), flow of control immediately returns.
If TRUE, the current application waits until the other program has terminated. If TRUE, the current application waits until the other program has terminated.
If execution is asynchronous, the return value is the process id, The return value is the process id, not the exit code of invoked program (for
otherwise it is a status value. A zero value indicates that the command could not this you should use wxProcess). A zero value indicates that the command could
be executed. not be executed.
If callback isn't NULL and if execution is asynchronous, If callback isn't NULL and if execution is asynchronous (note that callback
parameter can not be non NULL for synchronous execution),
\helpref{wxProcess::OnTerminate}{wxprocessonterminate} will be called when \helpref{wxProcess::OnTerminate}{wxprocessonterminate} will be called when
the process finishes. the process finishes.

View File

@@ -1,8 +1,18 @@
\section{\class{wxProcess}}\label{wxprocess} \section{\class{wxProcess}}\label{wxprocess}
This class contains a method which is invoked when a process finishes. The objects of this class are used in conjonction with
It can raise a \helpref{wxProcessEvent}{wxprocessevent} if wxProcess::OnTerminate \helpref{wxExecute}{wxexecute} function. When a wxProcess object is passed to
isn't overriden. wxExecute(), its \helpref{OnTerminate()}{wxprocessonterminate} virtual method
is called when the process terminates. This allows the program to be
(asynchronously) notified about the process termination and also retrieve its
exit status which is unavailable from wxExecute() in the case of
asynchronous execution.
Please note that if the process termination notification is processed by the
parent, it is responsible for deleting the wxProcess object which sent it.
However, if it is not processed, the object will delete itself and so the
library users should only delete those objects whose notifications have been
processed (and call \helpref{Detach()}{wxprocessdetach} for others).
\wxheading{Derived from} \wxheading{Derived from}
@@ -22,6 +32,10 @@ Constructs a process object. {\it id} is only used in the case you want to
use wxWindows events. It identifies this object, or another window that will use wxWindows events. It identifies this object, or another window that will
receive the event. receive the event.
If the {\it parent} parameter is different from NULL, it will receive
a wxEVT\_END\_PROCESS notification event (you should insert EVT\_END\_PROCESS
macro in the event table of the parent to handle it) with the given {\it id}.
\wxheading{Parameters} \wxheading{Parameters}
\docparam{parent}{The event handler parent.} \docparam{parent}{The event handler parent.}
@@ -34,12 +48,28 @@ receive the event.
Destroys the wxProcess object. Destroys the wxProcess object.
\membersection{wxProcess::Detach}\label{wxprocessdetach}
\func{void}{Detach}{\void}
Normally, a wxProcess object is deleted by its parent when it receives the
notification about the process termination. However, it might happen that the
parent object is destroyed before the external process is terminated (e.g. a
window from which this external process was launched is closed by the user)
and in this case it {\bf should not delete} the wxProcess object, but
{\bf should call Detach()} instead. After the wxProcess object is detached
from its parent, no notification events will be sent to the parent and the
object will delete itself upon reception of the process termination
notification.
\membersection{wxProcess::OnTerminate}\label{wxprocessonterminate} \membersection{wxProcess::OnTerminate}\label{wxprocessonterminate}
\constfunc{void}{OnTerminate}{\param{int}{ pid}} \constfunc{void}{OnTerminate}{\param{int}{ pid}, \param{int}{ status}}
It is called when the process with the pid {\it pid} finishes. It is called when the process with the pid {\it pid} finishes.
It raises a wxWindows event when it isn't overriden. It raises a wxWindows event when it isn't overriden.
\docparam{pid}{The pid of the process which ends.} \docparam{pid}{The pid of the process which has just terminated.}
\docparam{status}{The exit code of the process.}

View File

@@ -2,11 +2,11 @@
// Name: process.h // Name: process.h
// Purpose: wxProcess class // Purpose: wxProcess class
// Author: Guilhem Lavaux // Author: Guilhem Lavaux
// Modified by: // Modified by: Vadim Zeitlin to check error codes, added Detach() method
// Created: 24/06/98 // Created: 24/06/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) 1998 Guilhem Lavaux // Copyright: (c) 1998 Guilhem Lavaux
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PROCESSH__ #ifndef _WX_PROCESSH__
@@ -55,6 +55,10 @@ public:
virtual void OnTerminate(int pid, int status); virtual void OnTerminate(int pid, int status);
// detach from the parent - should be called by the parent if it's deleted
// before the process it started terminates
void Detach();
protected: protected:
int m_id; int m_id;
}; };

View File

@@ -2,11 +2,11 @@
// Name: process.cpp // Name: process.cpp
// Purpose: Process termination classes // Purpose: Process termination classes
// Author: Guilhem Lavaux // Author: Guilhem Lavaux
// Modified by: // Modified by: Vadim Zeitlin to check error codes, added Detach() method
// Created: 24/06/98 // Created: 24/06/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux // Copyright: (c) Guilhem Lavaux
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__ #ifdef __GNUG__
@@ -31,15 +31,23 @@ IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent)
wxProcess::wxProcess(wxEvtHandler *parent, int id) wxProcess::wxProcess(wxEvtHandler *parent, int id)
{ {
if (parent) if (parent)
SetNextHandler(parent); SetNextHandler(parent);
m_id = id; m_id = id;
} }
void wxProcess::OnTerminate(int pid, int status) void wxProcess::OnTerminate(int pid, int status)
{ {
wxProcessEvent event(m_id, pid, status); wxProcessEvent event(m_id, pid, status);
ProcessEvent(event); if ( !ProcessEvent(event) )
delete this;
//else: the object which processed the event is responsible for deleting
// us!
}
void wxProcess::Detach()
{
SetNextHandler(NULL);
} }

View File

@@ -96,7 +96,7 @@ int wxGetOsVersion(int *majorVsn, int *minorVsn)
{ {
if (majorVsn) *majorVsn = GTK_MAJOR_VERSION; if (majorVsn) *majorVsn = GTK_MAJOR_VERSION;
if (minorVsn) *minorVsn = GTK_MINOR_VERSION; if (minorVsn) *minorVsn = GTK_MINOR_VERSION;
return wxGTK; return wxGTK;
} }
@@ -123,11 +123,11 @@ char *wxGetUserHome( const wxString &user )
{ {
return ptr; return ptr;
} }
if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL) if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
{ {
who = getpwnam(ptr); who = getpwnam(ptr);
} }
/* We now make sure the the user exists! */ /* We now make sure the the user exists! */
if (who == NULL) if (who == NULL)
{ {
@@ -299,10 +299,10 @@ long wxExecute( char **argv, bool sync, wxProcess *process )
wxCHECK_MSG( *argv, 0, "can't exec empty command" ); wxCHECK_MSG( *argv, 0, "can't exec empty command" );
/* Create pipes */ /* Create pipes */
if (pipe(end_proc_detect) == -1) if (pipe(end_proc_detect) == -1)
{ {
wxLogSysError( "Pipe creation failed" ); wxLogSysError( "Pipe creation failed" );
return 0; return 0;
} }
/* fork the process */ /* fork the process */
@@ -311,65 +311,68 @@ long wxExecute( char **argv, bool sync, wxProcess *process )
#else #else
pid_t pid = fork(); pid_t pid = fork();
#endif #endif
if (pid == -1) if (pid == -1)
{ {
wxLogSysError( "Fork failed" ); wxLogSysError( "Fork failed" );
return 0; return 0;
} }
else if (pid == 0) else if (pid == 0)
{ {
// we're in child // we're in child
close(end_proc_detect[0]); // close reading side close(end_proc_detect[0]); // close reading side
// These three lines close the open file descriptors to
// to avoid any input/output which might block the process // These three lines close the open file descriptors to
// or irritate the user. If one wants proper IO for the sub- // to avoid any input/output which might block the process
// process, the "right thing to do" is to start an xterm executing // or irritate the user. If one wants proper IO for the sub-
// it. // process, the "right thing to do" is to start an xterm executing
close(STDIN_FILENO); // it.
close(STDOUT_FILENO); close(STDIN_FILENO);
close(STDERR_FILENO); close(STDOUT_FILENO);
close(STDERR_FILENO);
// some programs complain about sterr not being open, so // some programs complain about sterr not being open, so
// redirect them: // redirect them:
open("/dev/null", O_RDONLY); // stdin open("/dev/null", O_RDONLY); // stdin
open("/dev/null", O_WRONLY); // stdout open("/dev/null", O_WRONLY); // stdout
open("/dev/null", O_WRONLY); // stderr open("/dev/null", O_WRONLY); // stderr
#ifdef _AIX #ifdef _AIX
execvp ((const char *)*argv, (const char **)argv); execvp ((const char *)*argv, (const char **)argv);
#else #else
execvp (*argv, argv); execvp (*argv, argv);
#endif #endif
// there is no return after successful exec() // there is no return after successful exec()
wxLogSysError( "Can't execute '%s'", *argv); wxLogSysError( "Can't execute '%s'", *argv);
_exit(-1); _exit(-1);
} }
else else
{ {
// we're in parent // we're in parent
close(end_proc_detect[1]); // close writing side close(end_proc_detect[1]); // close writing side
data->tag = gdk_input_add(end_proc_detect[0], GDK_INPUT_READ, data->tag = gdk_input_add(end_proc_detect[0], GDK_INPUT_READ,
GTK_EndProcessDetector, (gpointer)data); GTK_EndProcessDetector, (gpointer)data);
data->pid = pid; data->pid = pid;
if (!sync) if (!sync)
{ {
data->process = process; data->process = process;
} }
else else
{ {
data->process = (wxProcess *) NULL; data->process = (wxProcess *) NULL;
data->pid = -(data->pid); data->pid = -(data->pid);
while (data->pid != 0) while (data->pid != 0)
wxYield(); wxYield();
delete data; delete data;
} }
// @@@ our return value indicates success even if execvp() in the child // @@@ our return value indicates success even if execvp() in the child
// failed! // failed!
return pid; return pid;
} }
} }
@@ -389,7 +392,7 @@ long wxExecute( const wxString& command, bool sync, wxProcess *process )
/* loop */ ; /* loop */ ;
long lRc = wxExecute(argv, sync, process); long lRc = wxExecute(argv, sync, process);
delete [] tmp; delete [] tmp;
return lRc; return lRc;

View File

@@ -96,7 +96,7 @@ int wxGetOsVersion(int *majorVsn, int *minorVsn)
{ {
if (majorVsn) *majorVsn = GTK_MAJOR_VERSION; if (majorVsn) *majorVsn = GTK_MAJOR_VERSION;
if (minorVsn) *minorVsn = GTK_MINOR_VERSION; if (minorVsn) *minorVsn = GTK_MINOR_VERSION;
return wxGTK; return wxGTK;
} }
@@ -123,11 +123,11 @@ char *wxGetUserHome( const wxString &user )
{ {
return ptr; return ptr;
} }
if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL) if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
{ {
who = getpwnam(ptr); who = getpwnam(ptr);
} }
/* We now make sure the the user exists! */ /* We now make sure the the user exists! */
if (who == NULL) if (who == NULL)
{ {
@@ -299,10 +299,10 @@ long wxExecute( char **argv, bool sync, wxProcess *process )
wxCHECK_MSG( *argv, 0, "can't exec empty command" ); wxCHECK_MSG( *argv, 0, "can't exec empty command" );
/* Create pipes */ /* Create pipes */
if (pipe(end_proc_detect) == -1) if (pipe(end_proc_detect) == -1)
{ {
wxLogSysError( "Pipe creation failed" ); wxLogSysError( "Pipe creation failed" );
return 0; return 0;
} }
/* fork the process */ /* fork the process */
@@ -311,65 +311,68 @@ long wxExecute( char **argv, bool sync, wxProcess *process )
#else #else
pid_t pid = fork(); pid_t pid = fork();
#endif #endif
if (pid == -1) if (pid == -1)
{ {
wxLogSysError( "Fork failed" ); wxLogSysError( "Fork failed" );
return 0; return 0;
} }
else if (pid == 0) else if (pid == 0)
{ {
// we're in child // we're in child
close(end_proc_detect[0]); // close reading side close(end_proc_detect[0]); // close reading side
// These three lines close the open file descriptors to
// to avoid any input/output which might block the process // These three lines close the open file descriptors to
// or irritate the user. If one wants proper IO for the sub- // to avoid any input/output which might block the process
// process, the "right thing to do" is to start an xterm executing // or irritate the user. If one wants proper IO for the sub-
// it. // process, the "right thing to do" is to start an xterm executing
close(STDIN_FILENO); // it.
close(STDOUT_FILENO); close(STDIN_FILENO);
close(STDERR_FILENO); close(STDOUT_FILENO);
close(STDERR_FILENO);
// some programs complain about sterr not being open, so // some programs complain about sterr not being open, so
// redirect them: // redirect them:
open("/dev/null", O_RDONLY); // stdin open("/dev/null", O_RDONLY); // stdin
open("/dev/null", O_WRONLY); // stdout open("/dev/null", O_WRONLY); // stdout
open("/dev/null", O_WRONLY); // stderr open("/dev/null", O_WRONLY); // stderr
#ifdef _AIX #ifdef _AIX
execvp ((const char *)*argv, (const char **)argv); execvp ((const char *)*argv, (const char **)argv);
#else #else
execvp (*argv, argv); execvp (*argv, argv);
#endif #endif
// there is no return after successful exec() // there is no return after successful exec()
wxLogSysError( "Can't execute '%s'", *argv); wxLogSysError( "Can't execute '%s'", *argv);
_exit(-1); _exit(-1);
} }
else else
{ {
// we're in parent // we're in parent
close(end_proc_detect[1]); // close writing side close(end_proc_detect[1]); // close writing side
data->tag = gdk_input_add(end_proc_detect[0], GDK_INPUT_READ, data->tag = gdk_input_add(end_proc_detect[0], GDK_INPUT_READ,
GTK_EndProcessDetector, (gpointer)data); GTK_EndProcessDetector, (gpointer)data);
data->pid = pid; data->pid = pid;
if (!sync) if (!sync)
{ {
data->process = process; data->process = process;
} }
else else
{ {
data->process = (wxProcess *) NULL; data->process = (wxProcess *) NULL;
data->pid = -(data->pid); data->pid = -(data->pid);
while (data->pid != 0) while (data->pid != 0)
wxYield(); wxYield();
delete data; delete data;
} }
// @@@ our return value indicates success even if execvp() in the child // @@@ our return value indicates success even if execvp() in the child
// failed! // failed!
return pid; return pid;
} }
} }
@@ -389,7 +392,7 @@ long wxExecute( const wxString& command, bool sync, wxProcess *process )
/* loop */ ; /* loop */ ;
long lRc = wxExecute(argv, sync, process); long lRc = wxExecute(argv, sync, process);
delete [] tmp; delete [] tmp;
return lRc; return lRc;