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 TRUE, the current application waits until the other program has terminated.
If execution is asynchronous, the return value is the process id,
otherwise it is a status value. A zero value indicates that the command could not
be executed.
The return value is the process id, not the exit code of invoked program (for
this you should use wxProcess). A zero value indicates that the command could
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
the process finishes.

View File

@ -1,8 +1,18 @@
\section{\class{wxProcess}}\label{wxprocess}
This class contains a method which is invoked when a process finishes.
It can raise a \helpref{wxProcessEvent}{wxprocessevent} if wxProcess::OnTerminate
isn't overriden.
The objects of this class are used in conjonction with
\helpref{wxExecute}{wxexecute} function. When a wxProcess object is passed to
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}
@ -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
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}
\docparam{parent}{The event handler parent.}
@ -34,12 +48,28 @@ receive the event.
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}
\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 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
// Purpose: wxProcess class
// Author: Guilhem Lavaux
// Modified by:
// Modified by: Vadim Zeitlin to check error codes, added Detach() method
// Created: 24/06/98
// RCS-ID: $Id$
// Copyright: (c) 1998 Guilhem Lavaux
// Licence: wxWindows license
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PROCESSH__
@ -55,6 +55,10 @@ public:
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:
int m_id;
};

View File

@ -2,11 +2,11 @@
// Name: process.cpp
// Purpose: Process termination classes
// Author: Guilhem Lavaux
// Modified by:
// Modified by: Vadim Zeitlin to check error codes, added Detach() method
// Created: 24/06/98
// RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux
// Licence: wxWindows license
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
@ -31,15 +31,23 @@ IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent)
wxProcess::wxProcess(wxEvtHandler *parent, int id)
{
if (parent)
SetNextHandler(parent);
if (parent)
SetNextHandler(parent);
m_id = id;
m_id = id;
}
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 (minorVsn) *minorVsn = GTK_MINOR_VERSION;
return wxGTK;
}
@ -123,11 +123,11 @@ char *wxGetUserHome( const wxString &user )
{
return ptr;
}
if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
if ((ptr = getenv("USER")) != NULL || (ptr = getenv("LOGNAME")) != NULL)
{
who = getpwnam(ptr);
}
/* We now make sure the the user exists! */
if (who == NULL)
{
@ -299,10 +299,10 @@ long wxExecute( char **argv, bool sync, wxProcess *process )
wxCHECK_MSG( *argv, 0, "can't exec empty command" );
/* Create pipes */
if (pipe(end_proc_detect) == -1)
if (pipe(end_proc_detect) == -1)
{
wxLogSysError( "Pipe creation failed" );
return 0;
wxLogSysError( "Pipe creation failed" );
return 0;
}
/* fork the process */
@ -311,65 +311,68 @@ long wxExecute( char **argv, bool sync, wxProcess *process )
#else
pid_t pid = fork();
#endif
if (pid == -1)
if (pid == -1)
{
wxLogSysError( "Fork failed" );
return 0;
}
else if (pid == 0)
else if (pid == 0)
{
// we're in child
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
// or irritate the user. If one wants proper IO for the sub-
// process, the "right thing to do" is to start an xterm executing
// it.
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// These three lines close the open file descriptors to
// to avoid any input/output which might block the process
// or irritate the user. If one wants proper IO for the sub-
// process, the "right thing to do" is to start an xterm executing
// it.
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// some programs complain about sterr not being open, so
// redirect them:
open("/dev/null", O_RDONLY); // stdin
open("/dev/null", O_WRONLY); // stdout
open("/dev/null", O_WRONLY); // stderr
open("/dev/null", O_WRONLY); // stdout
open("/dev/null", O_WRONLY); // stderr
#ifdef _AIX
execvp ((const char *)*argv, (const char **)argv);
#else
execvp (*argv, argv);
#endif
// there is no return after successful exec()
wxLogSysError( "Can't execute '%s'", *argv);
_exit(-1);
}
else
else
{
// we're in parent
close(end_proc_detect[1]); // close writing side
data->tag = gdk_input_add(end_proc_detect[0], GDK_INPUT_READ,
GTK_EndProcessDetector, (gpointer)data);
data->pid = pid;
if (!sync)
{
data->process = process;
}
else
{
data->process = (wxProcess *) NULL;
data->pid = -(data->pid);
// we're in parent
close(end_proc_detect[1]); // close writing side
data->tag = gdk_input_add(end_proc_detect[0], GDK_INPUT_READ,
GTK_EndProcessDetector, (gpointer)data);
data->pid = pid;
if (!sync)
{
data->process = process;
}
else
{
data->process = (wxProcess *) NULL;
data->pid = -(data->pid);
while (data->pid != 0)
wxYield();
while (data->pid != 0)
wxYield();
delete data;
}
delete data;
}
// @@@ our return value indicates success even if execvp() in the child
// failed!
return pid;
// @@@ our return value indicates success even if execvp() in the child
// failed!
return pid;
}
}
@ -389,7 +392,7 @@ long wxExecute( const wxString& command, bool sync, wxProcess *process )
/* loop */ ;
long lRc = wxExecute(argv, sync, process);
delete [] tmp;
return lRc;

View File

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