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:
parent
ca5c8b2df6
commit
7e84f02dfd
@ -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.
|
||||
|
||||
|
@ -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.}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user