From 7e84f02dfda7d5e3cf2cef1aa85169c55e8d4461 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 17 Feb 1999 17:56:59 +0000 Subject: [PATCH] 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 --- docs/latex/wx/function.tex | 9 ++-- docs/latex/wx/process.tex | 40 ++++++++++++++--- include/wx/process.h | 8 +++- src/common/process.cpp | 22 ++++++--- src/gtk/utilsgtk.cpp | 91 ++++++++++++++++++++------------------ src/gtk1/utilsgtk.cpp | 91 ++++++++++++++++++++------------------ 6 files changed, 155 insertions(+), 106 deletions(-) diff --git a/docs/latex/wx/function.tex b/docs/latex/wx/function.tex index 655af485a7..d4888be1db 100644 --- a/docs/latex/wx/function.tex +++ b/docs/latex/wx/function.tex @@ -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. diff --git a/docs/latex/wx/process.tex b/docs/latex/wx/process.tex index b09bb386ef..6d4ba8232c 100644 --- a/docs/latex/wx/process.tex +++ b/docs/latex/wx/process.tex @@ -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.} diff --git a/include/wx/process.h b/include/wx/process.h index dc4d5a43a9..b612306a66 100644 --- a/include/wx/process.h +++ b/include/wx/process.h @@ -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; }; diff --git a/src/common/process.cpp b/src/common/process.cpp index 2469953ed2..6440993d20 100644 --- a/src/common/process.cpp +++ b/src/common/process.cpp @@ -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); } diff --git a/src/gtk/utilsgtk.cpp b/src/gtk/utilsgtk.cpp index ba3988e154..fd92f99ba4 100644 --- a/src/gtk/utilsgtk.cpp +++ b/src/gtk/utilsgtk.cpp @@ -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); - - 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; } } @@ -389,7 +392,7 @@ long wxExecute( const wxString& command, bool sync, wxProcess *process ) /* loop */ ; long lRc = wxExecute(argv, sync, process); - + delete [] tmp; return lRc; diff --git a/src/gtk1/utilsgtk.cpp b/src/gtk1/utilsgtk.cpp index ba3988e154..fd92f99ba4 100644 --- a/src/gtk1/utilsgtk.cpp +++ b/src/gtk1/utilsgtk.cpp @@ -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); - - 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; } } @@ -389,7 +392,7 @@ long wxExecute( const wxString& command, bool sync, wxProcess *process ) /* loop */ ; long lRc = wxExecute(argv, sync, process); - + delete [] tmp; return lRc; -- 2.45.2