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.
\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}
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.}
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.}
// 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__
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;
};
// 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__
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);
}
{
if (majorVsn) *majorVsn = GTK_MAJOR_VERSION;
if (minorVsn) *minorVsn = GTK_MINOR_VERSION;
-
+
return wxGTK;
}
{
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)
{
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 */
#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);
-
- while (data->pid != 0)
- wxYield();
-
- delete data;
- }
-
- // @@@ our return value indicates success even if execvp() in the child
- // failed!
- return 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();
+
+ delete data;
+ }
+
+ // @@@ our return value indicates success even if execvp() in the child
+ // failed!
+ return pid;
}
}
/* loop */ ;
long lRc = wxExecute(argv, sync, process);
-
+
delete [] tmp;
return lRc;
{
if (majorVsn) *majorVsn = GTK_MAJOR_VERSION;
if (minorVsn) *minorVsn = GTK_MINOR_VERSION;
-
+
return wxGTK;
}
{
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)
{
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 */
#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);
-
- while (data->pid != 0)
- wxYield();
-
- delete data;
- }
-
- // @@@ our return value indicates success even if execvp() in the child
- // failed!
- return 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();
+
+ delete data;
+ }
+
+ // @@@ our return value indicates success even if execvp() in the child
+ // failed!
+ return pid;
}
}
/* loop */ ;
long lRc = wxExecute(argv, sync, process);
-
+
delete [] tmp;
return lRc;