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:
@@ -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.
|
||||||
|
|
||||||
|
@@ -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.}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user