2009-01-13 14:07 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)

* harbour/common.mak
  * harbour/source/rtl/Makefile
  * harbour/include/hbapifs.h
  * harbour/include/hbextern.ch
  + harbour/source/rtl/hbproces.c
  + harbour/source/rtl/hbprocfn.c
    + added C functions hb_fsOpenProcess(), hb_fsProcessValue(),
      hb_fsCloseProcess()
    + added .prg functions HB_OPENPROCESS(), HB_PROCESSVALUE(),
      HB_CLOSEPROCESS()
    Based on xHarbour code by Giancarlo Niccolai.
    Warning: it's possible that they will be changed in the future.
    Please test current implementation. Now few notes about it.
    Each handle returned by HB_OPENPROCESS() have to be closed
    by HB_PROCESSVALUE(). Even if process is killed by HB_CLOSEPROCESS()
    its handle is still open and HB_PROCESSVALUE() has to be executed.
    Type of handle depends on OS. In *nixes it's process PID. In MS-Windows
    it's HANDLE. HB_PROCESSVALUE() attach process exit result in *nixes
    cleaning zombie processes and in Windows closing the HANDLE. If you
    do not call this function then you will have resource leak.
    HB_CLOSEPROCESS() only sends quite request to the process but does
    not execute any cleanup code.
    All communication handles returned in parameters by reference by
    HB_OPENPROCESS() function have to be closed using FCLOSE() function.
    If hStdOut and hStdErr are references to the same variables then
    executing process stdout and stderr is redirected to the only one
    pipe. When handles for stdout, stderr and stdin are not given then
    executed process inherits them from parent process unless <lDetach>
    parameter is not given. In such case they are redirected to null
    device (/dev/null or NUL).
    The OS2 version is not tested. Please make tests.
    There is no support for DOS which is single process OS.
    In WinCE builds std{out,err,in} redirecting and process detaching does
    not work too.
    The parameters parsing should be updated. Now MS-Windows version uses
    native OS command line parsing and quoting by "" can be used for
    parameters with blank characters. I do not know any escape character
    which can be used to pass (") as parameter to MS-Windows application.
    In all other OS-es standard bourne shell rules are used. Parameters can
    be quoted by "" or '' and escape character is \. Quoting by '' disables
    special meaning of escape character. In OS2 where \ is path separator
    escaping and '' quoting is disabled so it works like in MS-Windows
    but I do not know if parameters divided by calling process are fully
    respected by low level API calls in this system.
This commit is contained in:
Przemyslaw Czerpak
2009-01-13 13:04:01 +00:00
parent a152f6391f
commit 3b6d1242e5
7 changed files with 914 additions and 3 deletions

View File

@@ -8,6 +8,52 @@
2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
*/
2009-01-13 14:07 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/common.mak
* harbour/source/rtl/Makefile
* harbour/include/hbapifs.h
* harbour/include/hbextern.ch
+ harbour/source/rtl/hbproces.c
+ harbour/source/rtl/hbprocfn.c
+ added C functions hb_fsOpenProcess(), hb_fsProcessValue(),
hb_fsCloseProcess()
+ added .prg functions HB_OPENPROCESS(), HB_PROCESSVALUE(),
HB_CLOSEPROCESS()
Based on xHarbour code by Giancarlo Niccolai.
Warning: it's possible that they will be changed in the future.
Please test current implementation. Now few notes about it.
Each handle returned by HB_OPENPROCESS() have to be closed
by HB_PROCESSVALUE(). Even if process is killed by HB_CLOSEPROCESS()
its handle is still open and HB_PROCESSVALUE() has to be executed.
Type of handle depends on OS. In *nixes it's process PID. In MS-Windows
it's HANDLE. HB_PROCESSVALUE() attach process exit result in *nixes
cleaning zombie processes and in Windows closing the HANDLE. If you
do not call this function then you will have resource leak.
HB_CLOSEPROCESS() only sends quite request to the process but does
not execute any cleanup code.
All communication handles returned in parameters by reference by
HB_OPENPROCESS() function have to be closed using FCLOSE() function.
If hStdOut and hStdErr are references to the same variables then
executing process stdout and stderr is redirected to the only one
pipe. When handles for stdout, stderr and stdin are not given then
executed process inherits them from parent process unless <lDetach>
parameter is not given. In such case they are redirected to null
device (/dev/null or NUL).
The OS2 version is not tested. Please make tests.
There is no support for DOS which is single process OS.
In WinCE builds std{out,err,in} redirecting and process detaching does
not work too.
The parameters parsing should be updated. Now MS-Windows version uses
native OS command line parsing and quoting by "" can be used for
parameters with blank characters. I do not know any escape character
which can be used to pass (") as parameter to MS-Windows application.
In all other OS-es standard bourne shell rules are used. Parameters can
be quoted by "" or '' and escape character is \. Quoting by '' disables
special meaning of escape character. In OS2 where \ is path separator
escaping and '' quoting is disabled so it works like in MS-Windows
but I do not know if parameters divided by calling process are fully
respected by low level API calls in this system.
2009-01-12 23:35 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/source/rtl/cdpapi.c
* harbour/source/rtl/langapi.c

View File

@@ -542,11 +542,13 @@ RTL_LIB_OBJS = \
$(OBJ_DIR)\hbgtcore$(OBJEXT) \
$(OBJ_DIR)\hbi18n$(OBJEXT) \
$(OBJ_DIR)\hbinet$(OBJEXT) \
$(OBJ_DIR)\hbstrsh$(OBJEXT) \
$(OBJ_DIR)\hbproces$(OBJEXT) \
$(OBJ_DIR)\hbprocfn$(OBJEXT) \
$(OBJ_DIR)\hbrandom$(OBJEXT) \
$(OBJ_DIR)\hbregex$(OBJEXT) \
$(OBJ_DIR)\hbregexc$(OBJEXT) \
$(OBJ_DIR)\hbrunfun$(OBJEXT) \
$(OBJ_DIR)\hbstrsh$(OBJEXT) \
$(OBJ_DIR)\hbtoken$(OBJEXT) \
$(OBJ_DIR)\hbzlib$(OBJEXT) \
$(OBJ_DIR)\idle$(OBJEXT) \

View File

@@ -258,7 +258,7 @@ typedef struct _HB_PATHNAMES
extern HB_EXPORT void hb_fsAddSearchPath( const char * szPath, HB_PATHNAMES ** pSearchList );
extern HB_EXPORT void hb_fsFreeSearchPath( HB_PATHNAMES * pSearchList );
extern HB_EXPORT BOOL hb_spFile( BYTE * pFilename, BYTE * pRetPath );
extern HB_EXPORT HB_FHANDLE hb_spOpen( BYTE * pFilename, USHORT uiFlags );
extern HB_EXPORT HB_FHANDLE hb_spCreate( BYTE * pFilename, ULONG ulAttr );
@@ -289,6 +289,14 @@ extern HB_EXPORT PHB_FFIND hb_fsFindFirst( const char * pszFileName, ULONG ulAtt
extern HB_EXPORT BOOL hb_fsFindNext( PHB_FFIND ffind );
extern HB_EXPORT void hb_fsFindClose( PHB_FFIND ffind );
/* functions to create, wait and terminate processes */
HB_FHANDLE hb_fsOpenProcess( const char *pszFilename,
HB_FHANDLE *phStdin, HB_FHANDLE *phStdout,
HB_FHANDLE *phStderr,
BOOL fDetach, ULONG *pulPID );
int hb_fsProcessValue( HB_FHANDLE hProcess, BOOL fWait );
BOOL hb_fsCloseProcess( HB_FHANDLE hProcess, BOOL fGentle );
/* Misc helper functions */
extern ULONG hb_fsAttrFromRaw( ULONG raw_attr );
extern ULONG hb_fsAttrToRaw( ULONG ulAttr );

View File

@@ -1144,6 +1144,9 @@ EXTERNAL HB_FNAMEEXISTS
EXTERNAL HB_FNAMEMERGE
EXTERNAL HB_FNAMESPLIT
EXTERNAL HB_DIRSCAN
EXTERNAL HB_OPENPROCESS
EXTERNAL HB_PROCESSVALUE
EXTERNAL HB_CLOSEPROCESS
EXTERNAL HB_GCALL
EXTERNAL HB_KEYCLEAR
EXTERNAL HB_KEYPUT

View File

@@ -67,11 +67,13 @@ C_SOURCES=\
hbgtcore.c \
hbi18n.c \
hbinet.c \
hbstrsh.c \
hbproces.c \
hbprocfn.c \
hbrandom.c \
hbregex.c \
hbregexc.c \
hbrunfun.c \
hbstrsh.c \
hbtoken.c \
hbzlib.c \
idle.c \

View File

@@ -0,0 +1,731 @@
/*
* $Id$
*/
/*
* Harbour Project source code:
* low level functions to create, wait and terminate processes
*
* Copyright 2009 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* www - http://www.harbour-project.org
* based on xHarbour code by
* Copyright 2003 Giancarlo Niccolai <gian@niccolai.ws>
* www - http://www.xharbour.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#define HB_OS_WIN_32_USED
/* #define HB_IO_WIN_OFF */
#include "hbapi.h"
#include "hbapifs.h"
#include "hbvm.h"
#if defined( HB_OS_UNIX )
# include <unistd.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
# include <fcntl.h>
#elif defined( HB_OS_OS2 ) || defined( HB_OS_UNIX ) || \
( defined( HB_OS_WIN_32 ) && !defined( HB_IO_WIN ) )
# include <io.h>
# include <process.h>
# include <fcntl.h>
#endif
#if defined( HB_OS_OS2 ) || defined( HB_OS_UNIX ) || \
( defined( HB_OS_WIN_32 ) && !defined( HB_IO_WIN ) )
/* convert command to argument list using standard bourne shell encoding:
* "" and '' can be used to group parameters with blank characters,
* the escape character is '\', quoting by '' disables escape character.
*/
static char ** hb_buildArgs( const char *pszFilename )
{
const char * src;
char ** argv, * dst, cQuote = 0;
int argc = 0;
while( HB_ISSPACE( *pszFilename ) )
++pszFilename;
src = pszFilename;
while( *src )
{
#if defined( HB_OS_UNIX )
if( *src == '\\' && cQuote != '\'' )
{
if( src[ 1 ] )
++src;
}
else
#endif
if( *src == cQuote )
cQuote = 0;
else if( cQuote == 0 )
{
#if defined( HB_OS_UNIX )
if( *src == '"' || *src == '\'' )
#else
if( *src == '"' )
#endif
cQuote = *src;
else if( HB_ISSPACE( *src ) )
{
while( HB_ISSPACE( src[ 1 ] ) )
++src;
if( src[ 1 ] )
++argc;
}
}
++src;
}
dst = ( char * ) hb_xgrab( strlen( pszFilename ) + 1 );
argv = ( char ** ) hb_xgrab( ( argc + 2 ) * sizeof( char * ) );
argv[ 0 ] = dst;
argv[ argc + 1 ] = NULL;
argc = 0;
cQuote = 0;
src = pszFilename;
while( *src )
{
#if defined( HB_OS_UNIX )
if( *src == '\\' && cQuote != '\'' )
{
if( src[ 1 ] )
{
*dst++ = src[ 1 ];
++src;
}
}
else
#endif
if( *src == cQuote )
cQuote = 0;
else if( cQuote != 0 )
*dst++ = *src;
else
{
#if defined( HB_OS_UNIX )
if( *src == '"' || *src == '\'' )
#else
if( *src == '"' )
#endif
cQuote = *src;
else if( HB_ISSPACE( *src ) )
{
*dst++ = '\0';
while( HB_ISSPACE( src[ 1 ] ) )
++src;
if( src[ 1 ] )
argv[ ++argc ] = dst;
}
else
*dst++ = *src;
}
++src;
}
*dst = 0;
return argv;
}
static void hb_freeArgs( char ** argv )
{
hb_xfree( argv[ 0 ] );
hb_xfree( argv );
}
#endif
HB_FHANDLE hb_fsOpenProcess( const char *pszFilename,
HB_FHANDLE *phStdin, HB_FHANDLE *phStdout,
HB_FHANDLE *phStderr,
BOOL fDetach, ULONG *pulPID )
{
HB_FHANDLE hResult = FS_ERROR;
HB_TRACE(HB_TR_DEBUG, ("hb_fsOpenProcess(%s, %p, %p, %p, %d, %p)", pszFilename, phStdin, phStdout, phStderr, fDetach, pulPID));
#if defined( HB_IO_WIN )
{
#if defined( HB_WINCE )
# define CreatePipe( hIn, hOut, sa, flags ) ( FALSE )
#endif
BOOL fError = FALSE;
HANDLE hPipes[ 6 ];
SECURITY_ATTRIBUTES sa;
int i;
for( i = 0; i < 6; ++i )
hPipes[ i ] = INVALID_HANDLE_VALUE;
memset( &sa, 0, sizeof( sa ) );
sa.nLength = sizeof( sa );
sa.bInheritHandle = TRUE;
if( phStdin != NULL )
fError = !CreatePipe( &hPipes[0], &hPipes[1], &sa, 0 );
if( !fError && phStdout != NULL )
fError = !CreatePipe( &hPipes[2], &hPipes[3], &sa, 0 );
if( !fError && phStderr != NULL )
{
if( phStdout == phStderr )
{
hPipes[4] = hPipes[2];
hPipes[5] = hPipes[3];
}
else
fError = !CreatePipe( &hPipes[4], &hPipes[5], &sa, 0 );
}
if( fError )
hb_fsSetIOError( FALSE, 0 );
else
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
DWORD dwFlags = 0;
#if defined(UNICODE)
LPWSTR lpCommand = hb_mbtowc( pszFilename );
#else
char * lpCommand = hb_strdup( pszFilename );
#endif
memset( &pi, 0, sizeof( pi ) );
memset( &si, 0, sizeof( si ) );
si.cb = sizeof( si );
if( fDetach )
{
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdInput = hPipes[ 0 ];
si.hStdOutput = hPipes[ 3 ];
si.hStdError = hPipes[ 5 ];
#ifdef DETACHED_PROCESS
dwFlags |= DETACHED_PROCESS;
#endif
}
else
{
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = phStdin ? hPipes[ 0 ] : GetStdHandle( STD_INPUT_HANDLE );
si.hStdOutput = phStdout ? hPipes[ 3 ] : GetStdHandle( STD_OUTPUT_HANDLE );
si.hStdError = phStderr ? hPipes[ 5 ] : GetStdHandle( STD_ERROR_HANDLE );
}
fError = ! CreateProcess( NULL, /* lpAppName */
lpCommand,
NULL, /* lpProcessAttr */
NULL, /* lpThreadAttr */
TRUE, /* bInheritHandles */
dwFlags, /* dwCreationFlags */
NULL, /* lpEnvironment */
NULL, /* lpCurrentDirectory */
&si,
&pi );
hb_fsSetIOError( !fError, 0 );
hb_xfree( lpCommand );
if( !fError )
{
if( phStdin != NULL )
{
*phStdin = ( HB_FHANDLE ) hPipes[ 1 ];
hPipes[ 1 ] = INVALID_HANDLE_VALUE;
}
if( phStdout != NULL )
{
*phStdout = ( HB_FHANDLE ) hPipes[ 2 ];
hPipes[ 2 ] = INVALID_HANDLE_VALUE;
}
if( phStderr != NULL )
{
*phStderr = ( HB_FHANDLE ) hPipes[ 4 ];
hPipes[ 4 ] = INVALID_HANDLE_VALUE;
}
if( pulPID )
*pulPID = pi.dwProcessId;
CloseHandle( pi.hThread );
hResult = ( HB_FHANDLE ) pi.hProcess;
}
}
for( i = phStdout == phStderr ? 3 : 5; i >= 0; --i )
{
if( hPipes[ i ] != INVALID_HANDLE_VALUE )
CloseHandle( hPipes[ i ] );
}
}
#elif defined( HB_OS_UNIX )
{
BOOL fError = FALSE;
HB_FHANDLE hPipeIn [ 2 ] = { FS_ERROR, FS_ERROR },
hPipeOut[ 2 ] = { FS_ERROR, FS_ERROR },
hPipeErr[ 2 ] = { FS_ERROR, FS_ERROR };
if( phStdin != NULL )
fError = pipe( hPipeIn ) != 0;
if( !fError && phStdout != NULL )
fError = pipe( hPipeOut ) != 0;
if( !fError && phStderr != NULL )
{
if( phStdout == phStderr )
{
hPipeErr[ 0 ] = hPipeOut[ 0 ];
hPipeErr[ 1 ] = hPipeOut[ 1 ];
}
else
fError = pipe( hPipeErr ) != 0;
}
if( !fError )
{
pid_t pid = fork();
if( pid == -1 )
fError = TRUE;
else if( pid != 0 ) /* parent process */
{
if( phStdin != NULL )
{
*phStdin = ( HB_FHANDLE ) hPipeIn[ 1 ];
hPipeIn[ 1 ] = FS_ERROR;
}
if( phStdout != NULL )
{
*phStdout = ( HB_FHANDLE ) hPipeOut[ 0 ];
hPipeOut[ 0 ] = FS_ERROR;
}
if( phStderr != NULL )
{
*phStderr = ( HB_FHANDLE ) hPipeErr[ 0 ];
hPipeErr[ 0 ] = FS_ERROR;
}
if( pulPID )
*pulPID = pid;
hResult = ( HB_FHANDLE ) pid;
}
else /* child process */
{
if( fDetach && ( !phStdin || !phStdout || !phStderr ) )
{
HB_FHANDLE hNull = open( "/dev/null", O_RDWR );
if( !phStdin )
dup2( hNull, 0 );
if( !phStdout )
dup2( hNull, 1 );
if( !phStderr )
dup2( hNull, 2 );
if( hNull != FS_ERROR )
close( hNull );
}
if( phStdin != NULL )
dup2( hPipeIn[ 0 ], 0 );
if( phStdout != NULL )
dup2( hPipeOut[ 1 ], 1 );
if( phStderr != NULL )
dup2( hPipeErr[ 1 ], 2 );
/* close all non std* handles */
{
int iMaxFD, i;
iMaxFD = sysconf( _SC_OPEN_MAX );
if( iMaxFD < 3 )
iMaxFD = 1024;
for( i = 3; i < iMaxFD; ++i )
close( i );
}
/* reset extended process attributes */
setuid( getuid() );
setgid( getgid() );
/* execute command */
{
#if 0
char * argv[4];
argv[0] = ( char * ) "sh";
argv[1] = ( char * ) "-c";
argv[2] = ( char * ) pszFilename;
argv[3] = ( char * ) 0;
execv( "/bin/sh", argv );
#else
char ** argv;
argv = hb_buildArgs( pszFilename );
execv( argv[ 0 ], argv );
hb_freeArgs( argv );
#endif
exit(1);
}
}
}
hb_fsSetIOError( !fError, 0 );
if( hPipeIn[ 0 ] != FS_ERROR )
close( hPipeIn[ 0 ] );
if( hPipeIn[ 1 ] != FS_ERROR )
close( hPipeIn[ 1 ] );
if( hPipeOut[ 0 ] != FS_ERROR )
close( hPipeOut[ 0 ] );
if( hPipeOut[ 1 ] != FS_ERROR )
close( hPipeOut[ 1 ] );
if( phStdout != phStderr )
{
if( hPipeErr[ 0 ] != FS_ERROR )
close( hPipeErr[ 0 ] );
if( hPipeErr[ 1 ] != FS_ERROR )
close( hPipeErr[ 1 ] );
}
}
#elif defined( HB_OS_OS2 ) || defined( HB_OS_WIN_32 )
{
#if defined( HB_OS_WIN_32 )
# define pid_t int
# define _hb_pipe( e, p ) do { \
(e) = _pipe( (p), 2048, _O_BINARY ) != 0; \
} while( 0 )
#elif defined( HB_OS_OS2 )
# define _hb_pipe( e, p ) do { \
(e) = pipe( (p) ) != 0; \
if( !(e) ) \
{ \
setmode( (p)[ 0 ], O_BINARY ); \
setmode( (p)[ 1 ], O_BINARY ); \
} \
} while( 0 )
#endif
BOOL fError = FALSE;
HB_FHANDLE hPipeIn [ 2 ] = { FS_ERROR, FS_ERROR },
hPipeOut[ 2 ] = { FS_ERROR, FS_ERROR },
hPipeErr[ 2 ] = { FS_ERROR, FS_ERROR };
if( phStdin != NULL )
{
_hb_pipe( fError, hPipeIn );
}
if( !fError && phStdout != NULL )
{
_hb_pipe( fError, hPipeOut );
}
if( !fError && phStderr != NULL )
{
if( phStdout == phStderr )
{
hPipeErr[ 0 ] = hPipeOut[ 0 ];
hPipeErr[ 1 ] = hPipeOut[ 1 ];
}
else
{
_hb_pipe( fError, hPipeErr );
}
}
if( !fError )
{
int hStdIn, hStdOut, hStdErr;
char ** argv;
pid_t pid;
hStdIn = dup( 0 );
hStdOut = dup( 1 );
hStdErr = dup( 2 );
if( fDetach && ( !phStdin || !phStdout || !phStderr ) )
{
HB_FHANDLE hNull = open( "NUL:", O_RDWR );
if( !phStdin )
dup2( hNull, 0 );
if( !phStdout )
dup2( hNull, 1 );
if( !phStderr )
dup2( hNull, 2 );
if( hNull != FS_ERROR )
close( hNull );
}
if( phStdin != NULL )
dup2( hPipeIn[ 0 ], 0 );
if( phStdout != NULL )
dup2( hPipeOut[ 1 ], 1 );
if( phStderr != NULL )
dup2( hPipeErr[ 1 ], 2 );
argv = hb_buildArgs( pszFilename );
#if defined( _MSC_VER ) || defined( __LCC__ ) || \
defined( __XCC__ ) || defined( __POCC__ )
pid = _spawnvp( _P_NOWAIT, argv[ 0 ], argv );
#elif defined( __MINGW32__ )
pid = spawnvp( P_NOWAIT, argv[ 0 ], ( const char * const * ) argv );
#else
pid = spawnvp( P_NOWAIT, argv[ 0 ], ( char * const * ) argv );
#endif
hb_freeArgs( argv );
dup2( hStdIn, 0 );
dup2( hStdOut, 1 );
dup2( hStdErr, 2 );
if( pid < 0 )
fError = TRUE;
else if( pid != 0 ) /* parent process */
{
if( phStdin != NULL )
{
*phStdin = ( HB_FHANDLE ) hPipeIn[ 1 ];
hPipeIn[ 1 ] = FS_ERROR;
}
if( phStdout != NULL )
{
*phStdout = ( HB_FHANDLE ) hPipeOut[ 0 ];
hPipeOut[ 0 ] = FS_ERROR;
}
if( phStderr != NULL )
{
*phStderr = ( HB_FHANDLE ) hPipeErr[ 0 ];
hPipeErr[ 0 ] = FS_ERROR;
}
if( pulPID )
*pulPID = pid;
hResult = ( HB_FHANDLE ) pid;
}
}
hb_fsSetIOError( !fError, 0 );
if( hPipeIn[ 0 ] != FS_ERROR )
close( hPipeIn[ 0 ] );
if( hPipeIn[ 1 ] != FS_ERROR )
close( hPipeIn[ 1 ] );
if( hPipeOut[ 0 ] != FS_ERROR )
close( hPipeOut[ 0 ] );
if( hPipeOut[ 1 ] != FS_ERROR )
close( hPipeOut[ 1 ] );
if( phStdout != phStderr )
{
if( hPipeErr[ 0 ] != FS_ERROR )
close( hPipeErr[ 0 ] );
if( hPipeErr[ 1 ] != FS_ERROR )
close( hPipeErr[ 1 ] );
}
}
#else
{
int TODO; /* TODO: for given platform */
HB_SYMBOL_UNUSED( pszFileName );
HB_SYMBOL_UNUSED( phStdin );
HB_SYMBOL_UNUSED( phStdout );
HB_SYMBOL_UNUSED( phStderr );
HB_SYMBOL_UNUSED( fDetach );
HB_SYMBOL_UNUSED( pulPID );
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#endif
return hResult;
}
int hb_fsProcessValue( HB_FHANDLE hProcess, BOOL fWait )
{
int iRetStatus = -1;
HB_TRACE(HB_TR_DEBUG, ("hb_fsProcessValue(%p, %d)", ( void * ) ( HB_PTRDIFF ) hProcess, fWait));
#if defined( HB_IO_WIN )
{
BOOL fError = TRUE;
DWORD dwResult;
HANDLE hProc = ( HANDLE ) hb_fsGetOsHandle( hProcess );
if( hProc )
{
hb_vmUnlock();
dwResult = WaitForSingleObject( hProc, fWait ? INFINITE : 0 );
if( dwResult == WAIT_OBJECT_0 )
{
fError = !GetExitCodeProcess( hProc, &dwResult );
iRetStatus = !fError ? ( int ) dwResult : -2;
}
hb_fsSetIOError( !fError, 0 );
if( !fError )
CloseHandle( hProc );
hb_vmLock();
}
else
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#elif defined( HB_OS_UNIX ) || ( defined( HB_OS_OS2 ) && defined( __GNUC__ ) )
{
int iStatus;
pid_t pid = ( pid_t ) hProcess;
if( pid > 0 )
{
hb_vmUnlock();
iRetStatus = waitpid( pid, &iStatus, fWait ? 0 : WNOHANG );
hb_fsSetIOError( iRetStatus >= 0, 0 );
#ifdef ERESTARTSYS
if( iRetStatus < 0 && errno != ERESTARTSYS)
#else
if( iRetStatus < 0 )
#endif
iRetStatus = -2;
else if( iRetStatus == 0 )
iRetStatus = -1;
else
iRetStatus = WIFEXITED( iStatus ) ? WEXITSTATUS( iStatus ) : 0;
hb_vmLock();
}
else
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#elif defined( HB_OS_OS2 ) || defined( HB_OS_WIN_32 )
{
int iPid = ( int ) hProcess;
HB_SYMBOL_UNUSED( fWait );
if( iPid > 0 )
{
hb_vmUnlock();
#if defined( __BORLANDC__ )
iPid = cwait( &iRetStatus, iPid, 0 );
#else
iPid = _cwait( &iRetStatus, iPid, 0 );
#endif
hb_fsSetIOError( iPid > 0, 0 );
if( iPid != ( int ) hProcess )
iRetStatus = -1;
hb_vmLock();
}
else
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#else
{
int TODO; /* TODO: for given platform */
HB_SYMBOL_UNUSED( hProcess );
HB_SYMBOL_UNUSED( fWait );
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#endif
return iRetStatus;
}
/* Closes/kills process. The handle is still valid until you
* catch it with hb_fsProcessValue.
*/
BOOL hb_fsCloseProcess( HB_FHANDLE hProcess, BOOL fGentle )
{
BOOL fResult = FALSE;
HB_TRACE(HB_TR_DEBUG, ("hb_fsCloseProcess(%p, %d)", ( void * ) ( HB_PTRDIFF ) hProcess, fGentle));
#if defined( HB_IO_WIN )
{
HANDLE hProc = ( HANDLE ) hb_fsGetOsHandle( hProcess );
if( hProc )
{
if( TerminateProcess( hProc, fGentle ? 0 : 1 ) )
fResult = TRUE;
hb_fsSetIOError( fResult, 0 );
}
else
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#elif defined( HB_OS_UNIX ) || ( defined( HB_OS_OS2 ) && defined( __GNUC__ ) )
{
pid_t pid = ( pid_t ) hProcess;
if( pid > 0 )
{
if( kill( pid, fGentle ? SIGTERM : SIGKILL ) == 0 )
fResult = TRUE;
hb_fsSetIOError( fResult, 0 );
}
else
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#elif defined( HB_OS_WIN_32 )
{
HANDLE hProc = OpenProcess( PROCESS_TERMINATE, FALSE, hProcess );
if( hProc )
{
if( TerminateProcess( hProc, fGentle ? 0 : 1 ) )
fResult = TRUE;
hb_fsSetIOError( fResult, 0 );
CloseHandle( hProc );
}
else
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#else
{
int TODO; /* TODO: for given platform */
HB_SYMBOL_UNUSED( hProcess );
HB_SYMBOL_UNUSED( fGentle );
hb_fsSetError( ( USHORT ) FS_ERROR );
}
#endif
return fResult;
}

View File

@@ -0,0 +1,119 @@
/*
* $Id$
*/
/*
* Harbour Project source code:
* .prg level functions to create, wait and terminate processes
*
* Copyright 2009 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* www - http://www.harbour-project.org
* based on xHarbour code by
* Copyright 2003 Giancarlo Niccolai <gian@niccolai.ws>
* www - http://www.xharbour.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#include "hbapi.h"
#include "hbapifs.h"
#include "hbapierr.h"
HB_FUNC( HB_OPENPROCESS )
{
const char *szName = hb_parc( 1 );
PHB_ITEM pStdIn = hb_param( 2, HB_IT_BYREF );
PHB_ITEM pStdOut = hb_param( 3, HB_IT_BYREF );
PHB_ITEM pStdErr = hb_param( 4, HB_IT_BYREF );
BOOL fDetach = hb_parl( 5 );
HB_FHANDLE hStdIn, *phStdIn, hStdOut, *phStdOut, hStdErr, *phStdErr;
HB_FHANDLE hProcess;
ULONG ulPID;
if( szName &&
( pStdIn || ISNIL( 2 ) ) &&
( pStdOut || ISNIL( 3 ) ) &&
( pStdErr || ISNIL( 4 ) ) &&
( ISLOG( 5 ) || ISNIL( 5 ) ) &&
( ISBYREF( 6 ) || ISNIL( 6 ) ) &&
( !pStdIn || ( pStdIn != pStdOut && pStdIn != pStdErr ) ) )
{
phStdIn = pStdIn ? &hStdIn : NULL;
phStdOut = pStdOut ? &hStdOut : NULL;
phStdErr = pStdErr ? ( pStdOut == pStdErr ? phStdOut : &hStdErr ) : NULL;
hProcess = hb_fsOpenProcess( szName, phStdIn, phStdOut, phStdErr,
fDetach, &ulPID );
if( hProcess != FS_ERROR )
{
if( phStdIn )
hb_stornint( ( HB_NHANDLE ) *phStdIn, 2 );
if( phStdOut )
hb_stornint( ( HB_NHANDLE ) *phStdOut, 3 );
if( phStdErr && phStdOut != phStdErr )
hb_stornint( ( HB_NHANDLE ) *phStdErr, 4 );
hb_stornint( ulPID, 6 );
}
hb_retnint( ( HB_NHANDLE ) hProcess );
}
else
hb_errRT_BASE_SubstR( EG_ARG, 4001, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( HB_PROCESSVALUE )
{
HB_FHANDLE hProcess = hb_numToHandle( hb_parnint( 1 ) );
if( hProcess != 0 && hProcess != FS_ERROR && ( hb_pcount() < 2 || ISLOG( 2 ) ) )
hb_retni( hb_fsProcessValue( hProcess, hb_pcount() < 2 || hb_parl( 2 ) ) );
else
hb_errRT_BASE_SubstR( EG_ARG, 4001, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( HB_CLOSEPROCESS )
{
HB_FHANDLE hProcess = hb_numToHandle( hb_parnint( 1 ) );
if( hProcess != 0 && hProcess != FS_ERROR && ( hb_pcount() < 2 || ISLOG( 2 ) ) )
hb_retl( hb_fsCloseProcess( hProcess, hb_pcount() < 2 || hb_parl( 2 ) ) );
else
hb_errRT_BASE_SubstR( EG_ARG, 4001, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}