Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Running an external program from FoxPro and waiting for its terminatio 2

Status
Not open for further replies.

Hannes214

IS-IT--Management
Jan 30, 2006
45
DE
Hi

i have to insert the results of an external programm for calculation the vibration of generators into our software.
The problem is, i have to wait, until the programm has finish the calculation, wrote the results to an file an close the file after some seconds...

Can someone help me?
 
If this external program is going to create a file when it's finished then you could sit in a loop using FILE() to check whether that file exists.

You'll need some sort of timer to stop the loop when it's obvious that the other program has crashed.

Geoff Franklin
 
Hi,

I do something similar with back-ups - using a zip program.

I write the commands to a batch file, then execute it using a run statement like this:

Code:
SET CONSOLE OFF
INSTRUCTION = "C:\BACKIT.BAT"
SET ALTE TO ("C:\BACKIT.BAT")
SET ALTE ON
CLOSE DATA ALL
?? "@ECHO OFF"
** do something in the batch file here
?  "Echo *** Done ***"
?  "Pause"
SET ALTE OFF
SET ALTE TO
SET CONSOLE ON
RUN &INSTRUCTION



Regards

Griff
Keep [Smile]ing
 
You could use WSH to Run the application and wait till finish:
Code:
#define SW_NORMAL 1
#define SW_MINIMIZED 2
#define SW_MAXIMIZED 3

oWSShell = CREATEOBJECT("WScript.Shell")
oWSShell.Run(full_path_to_ext_application,SW_NORMAL,.T.)

Borislav Borissov
 
thx for so much replies

@bborissov
that works great.. thx :)
 
Hannes214

Aa an alternative and it may not suit your application, if you change Borislav's code example to
Code:
[COLOR=blue] 
oWSShell.Run(full_path_to_ext_application,SW_NORMAL,.F.)[/color]
you will return control immediately to VFP.

You can then monitor the progress of the building of your output file by utilising some of the code in the following example.

The code also allows a user to cancel out of the operation whilst also displaying the file size on screen.

This helps where large files are being built by indicating the state of the build activity - you may also need to add another DO WHIL... loop before the code example to ensure the file exists before running the rest of the code.

The existence of the file is no indication that the file is complete.
Code:
[COLOR=blue]LPARAMETERS tcMethod

WITH THIS
[tab].nAnswer = 0 [COLOR=green]&& Reset value[/color]
[tab].cmdCancel.Enabled = .T.
[tab].cmdCancel.Refresh()	
[tab]DO WHILE .T. [COLOR=green]&& Wait for PS print to complete[/color]
[tab][tab]DOEVENTS
[tab][tab].nValue = INKEY(0.06,[HM]) [COLOR=green]&&	Value to test for mouse click[/color]
[tab][tab]IF .nValue = 151 AND .lCancelButton	
[tab][tab][tab].mQueryClick(tcMethod)
[tab][tab][tab]IF .nAnswer = 2
[tab][tab][tab][tab]EXIT
[tab][tab][tab]ENDI
[tab][tab]ENDI

[tab][tab]ADIR(laTemp,.cTempPsFile)
[tab][tab].lblLabel2.Caption  = ;
[tab][tab][Creating postscript file - ]	;
[tab][tab][tab]+ ALLTRIM(.mBytes2KB(laTemp[2]))	;
[tab][tab][tab]+ [ bytes written]

[tab][tab].nNo = FOPEN(.cTempPsFile,12)
[tab][tab]IF .nNo = -1 [COLOR=green]&& Check for error opening file[/color]
[tab][tab][tab]FCLOSE(.nNo) [COLOR=green]&& Close file[/color]
[tab][tab]ELSE
[tab][tab][tab]FCLOSE(.nNo) [COLOR=green]&& Close file[/color]
[tab][tab][tab]EXIT [COLOR=green]&& Exit loop[/color]
[tab][tab]ENDIF
[tab]ENDDO
[tab].cmdCancel.Enabled = .F.	
[tab].cmdCancel.Refresh()

[tab]ADIR(laTemp,.cTempPsFile)
[tab].lblLabel2.Caption  = ;
[tab][tab][Created postscript file - ]	;
[tab][tab]+ ALLTRIM(.mBytes2KB(laTemp[2]));
[tab][tab]+ [ bytes written]

[tab]INKEY(0.1)

ENDWITH[/color]

FAQ184-2483 - answering getting answered.​
Chris [pc2]
PDFcommander[sup]tm[/sup].net
PDFcommander[sup]tm[/sup].com
 

Picking up on a point that Geoff made earlier about the external app crashing, you can add the following code to the a DO WHILE.. loop
Code:
[COLOR=blue]lnSeconds = SECONDS()
DO WHILE .T.
[tab]IF SECONDS() > lnSeconds + USER.timeout
[tab][tab]llErrorTimedOut = .T.
[tab][tab]EXIT
[tab]ENDI	
[tab][COLOR=green]* Code[/color]
ENDDO[/color]
USER.timeout in this example is determined by the user - you need to ensure the value is high enough to prevent a long process from timing out incorrectly but short enough to ensure it functions as intended.

On a a potentionally long process you can always hard code a value such as
Code:
[COLOR=blue]IF SECONDS() > lnSeconds + USER.timeout + 300[/color]

FAQ184-2483 - answering getting answered.​
Chris [pc2]
PDFcommander[sup]tm[/sup].net
PDFcommander[sup]tm[/sup].com
 
Chris

Dumb question I'm sure - but...

Is it generally safe to assume that most machines will have the scripting components installed these days - or do some people remove them for 'security reasons' i.e. to spoil your day!

Martin

Regards

Griff
Keep [Smile]ing
 
No, Generaly you could not assume that. In some cases SysAdmins remove Scripting from users computers. They think this will improve security.

Borislav Borissov
 
Griff

Certainly not a dumb question - probably more common than we think.

Personally I use ShellExecute() where one needs control to be returned immediately to VFP and CreateProcess() where one wants the other app to complete.

The reason for suggesting the alternative posted is really to show a user that something is actually happening! [smile]

FAQ184-2483 - answering getting answered.​
Chris [pc2]
PDFcommander[sup]tm[/sup].net
PDFcommander[sup]tm[/sup].com
 
Here it is a class Create by Ed Rauh. This class didn't use Scripting but pure API functions:
Code:
**************************************************
*-- Class:        api_apprun (e:\processclass\process.vcx)
*-- ParentClass:  custom
*-- BaseClass:    custom
*-- Created by Ed Rauh 
***************************************************
DEFINE CLASS api_apprun AS custom

	* Process handle for process started by this object
	PROTECTED inprocesshandle
	inprocesshandle = .NULL.
	* Initial thread handle for process started by this object
	PROTECTED inthreadhandle
	inthreadhandle = .NULL.
	* Command line to execute to start this process
	iccommandline = (space(0))
	* Dir to start process from
	iclaunchdir = (space(0))
	* Window mode to use at process startup, one of:
	*	(empty)	Executable's default window mode
	*	NOR		ShowWindow Normal 0x1
	*	MIN		ShowWindow Minimized 0x2
	*	MAX		ShowWindow Maximumized 0x3
	*	HID		ShowWindow Hidden 0x0
	*			in this mode, there is no hookable WinMain
	icwindowmode = (space(0))
	*	Last error encountered desciptor (output)
	icerrormesage = (space(0))
	Name = "api_apprun"
	icerrormessage = .F.


	PROCEDURE LaunchApp
		*  Launch executable by CreateProcess() and return immediately
		LOCAL cCommandLine, uFromDir, cWindowMode
		WITH This
			.icErrorMessage = ''
			IF TYPE('.icCommandLine') # 'C'
				*	Command line must be a character string
				.icErrorMessage = 'icCommandLine must be set, and a string value'
				RETURN .F.
			ELSE
				cCommandLine = ALLTRIM(.icCommandLine)
			ENDIF
			IF TYPE('.icLaunchDir') # 'C' OR EMPTY(.icLaunchDir)
				*	If not a character string, pass a null pointer, defaulting to Current Working Dir
				uFromDir = 0
			ELSE
				*	Otherwise, null pad the string
				uFromDir = .icLaunchDir + CHR(0)
			ENDIF
			IF TYPE('.icWindowMode') # 'C'
				*	If not passed, set to null string
				cWindowMode = ''
			ELSE
				*	Translate the passed window mode to uppercase
				cWindowMode = UPPER(.icWindowMode)
			ENDIF
			*	This API call does the work.  The parameters are as follows:
			*		lpszModuleName - ptr-> file name of module to execute.  
			*		  Since we aren't launching .CPLs, do not use
			*		lpszCommandLine - ptr-> command to execute, as passed in method
			*		lpSecurityAttributesProcess - ptr-> SECURITY_ATTRIBUTES structure for Process.  
			*		  Pass a null pointer
			*		lpSecurityAttributesThread - ptr-> SECURITY_ATTRIBUTES structure for first thread.  
			*		  Pass a null pointer
			*		bInheritHandles - whether or not chlid inherits parent handles.  
			*		  Since no SECURITY_ATTRIBUTES passed, default to FALSE
			*		dwCreateFlags - Process Creation Mode flag set.  
			*		  We use the default mode at normal priority, ie 0
			*		lpvEnvironment	- ptr-> a set of environment strings as if a MULTI_SZ.  
			*		  We don't set, so pass a null pointer
			*		lpszStartupDir - ptr-> the starting directory.  
			*		  If none provided to method, pass a null pointer
			*		lpStartInfo - ptr-> a STARTUPINFO structure.  
			*		  We use one structure member at times.
			*		lpProcessInfo - ptr-> a PROCESS_INFORMATION structure, used to return PID/PHANDLE detail.  
			*		  We use one member to retain the Process handle, and destroy the thread handle
			DECLARE SHORT CreateProcess IN WIN32API AS CrPr ;
				STRING lpszModuleName, ;
				STRING @lpszCommandLine, ;
				STRING lpSecurityAttributesProcess, ;
				STRING lpSecurityAttributesThread, ;
				SHORT bInheritHandles, ;
				INTEGER dwCreateFlags, ;
				STRING lpvEnvironment, ;
				STRING lpszStartupDir, ;
				STRING @lpStartInfo, ;
				STRING @lpProcessInfo

			LOCAL cProcessInfo, cStartUpInfo

			*	Make default Structures for the CreateProcess call
			*
			*	ProcessInfo -	struc, 4 DWORDs, a Process Handle, a Thread Handle, a ProcessID and a ThreadID
			*					we save the Process and Thread Handles in member properties to ensure that
			*					they are properly disposed at Destroy by CloseHandle().  We dispose of the
			*					thread handle immediately

			cProcessInfo = REPL(CHR(0),16)

			*	StartUpInfo is a 68 byte long complex structure;  we either have 68 bytes with a cb member (byte 1) 68
			*	or with cb of 68, dwFlag low order byte (byte 45) of 1, and low order byte wShowWindow (byte 49) set to
			*	the SW_ value appropriate for the Window Mode desired.

			DO CASE
			CASE cWindowMode = 'HID'
				*	Hide - use STARTF_USESHOWFLAG and value of 0
				cStartUpInfo = CHR(68) + ;
								REPL(CHR(0),43) + ;
								CHR(1) + ;
								REPL(CHR(0),23)
			CASE cWindowMode = 'NOR'
				*	Normal - use STARTF_USESHOWFLAG and value of 1
				cStartUpInfo = CHR(68) + ;
								REPL(CHR(0),43) + ;
								CHR(1) + ;
								REPL(CHR(0),3) + ;
								CHR(1) + ;
								REPL(CHR(0),19)
			CASE cWindowMode = 'MIN'
				*	Minimize - use STARTF_USESHOWFLAG and value of 2
				cStartUpInfo = CHR(68) + ;
								REPL(CHR(0),43) + ;
								CHR(1) +  ;
								REPL(CHR(0),3) + ;
								CHR(2) + ;
								REPL(CHR(0),19)
			CASE cWindowMode = 'MAX'
				*	Maximize - use STARTF_USESHOWFLAG and value of 3
				cStartUpInfo = CHR(68) + ;
								REPL(CHR(0),43) + ;
								CHR(1) +  ;
								REPL(CHR(0),3) + ;
								CHR(3) + ;
								REPL(CHR(0),19)
			OTHERWISE
				*	Use default of application
				cStartUpInfo = CHR(68) + REPL(CHR(0),67)
			ENDCASE
			*	Do it!
			LOCAL lResult
			lResult = CrPr(	0, ;
							cCommandLine, ;
							0, 0, 0, 0, 0, ;
							uFromDir, ;
							@cStartUpInfo, ;
							@cProcessInfo)
			*	Strip the handles from the PROCESS_INFORMATION structure and save in private properties
			IF lResult = 1
				.ParseProcessInfoStruc(cProcessInfo)
				RETURN .T.
			ELSE
				.icErrorMessage = 'Process Specified by icCommandLine could not be started'
				RETURN .F.
			ENDIF
		ENDWITH
	ENDPROC


	PROCEDURE LaunchAppAndWait
		*	Invoke LaunchApp(), and then wait on the process to terminate before returning control
		#DEFINE cnINFINITE 		0xFFFFFFFF
		#DEFINE cnHalfASecond	500	&& milliseconds
		#DEFINE cnTimedOut		258	&& 0x0102
		*	We need some API calls, declare here
		*	GetCurrentProcess returns the pseudohandle of the current process (ie VFP instance)
		DECLARE INTEGER GetCurrentProcess IN WIN32API AS GetCurrProc
		*	WaitForIdleInput waits until the application is instantiated and at it's event loop
		DECLARE INTEGER WaitForInputIdle IN WIN32API AS WaitInpIdle ;
			INTEGER nProcessHandle, ;
			INTEGER nWaitForDuration
		*	WaitForSingleObject waits until the handle in parm 1 is signalled or the timeout period expires
		DECLARE INTEGER WaitForSingleObject IN WIN32API AS WaitOnAppExit ;
			INTEGER hProcessHandle, ;
			INTEGER dwTimeOut
		*	Save the Process handle if any and the result of LaunchApp
		*	Fire the app and save the process handle
		LOCAL uResult
		uResult = 0
		WITH This
			.icErrorMessage = ''
			IF .LaunchApp()
				uResult = 1
				*	It's been launched;  wait until we're idling along
				=WaitInpIdle(GetCurrProc(),cnINFINITE)
				*	As long as the other process exists, wait for it
				DO WHILE WaitOnAppExit(.inProcessHandle, cnHalfASecond) = cnTimedOut
					*	Give us an out in case the other app hangs - let <Esc> terminate waits
					IF INKEY() = 27
						*	Still running but we aren't waiting - return a -1 as a warning
						.icErrorMessage = 'Process started but user did not wait on termination'
						uResult = 0
						EXIT
					ENDIF
				ENDDO
			ELSE
				*	Return 0 to indicate failure
				uResult = 0
			ENDIF
		ENDWITH
		RETURN (uResult = 1)
	ENDPROC


	PROCEDURE CheckProcessxitCode
		*	examine the Process handle object's termination code member
		*	Provide the user with the option to examine another process
		*	termination code by passing an explicit handle, otherwise
		*	use the object's process instance
		LPARAMETER nProcessToCheck
		IF TYPE('nProcessToCheck') # 'N'
			nProcessToCheck = this.inProcessHandle
		ENDIF
		DECLARE SHORT GetExitCodeProcess IN Win32API AS CheckExitCode ;
			INTEGER hProcess, ;
			INTEGER @lpdwExitCode
		LOCAL nExitCode
		nExitCode = 0
		IF ! ISNULL(nProcessToCheck)
			IF CheckExitCode(nProcessToCheck, @nExitCode) = 1
				*	We retrieved an exit code (259 means still running, tho)
				RETURN nExitCode
			ELSE
				*	Process did not exist in process table - no exit status
				this.icErrorMessage = 'Process to check not in active Process Table'
				RETURN NULL
			ENDIF
		ELSE
			this.icErrorMessage = 'NULL process handle passed to CheckProcessExitCode()'
			RETURN NULL
		ENDIF
	ENDPROC

	PROTECTED PROCEDURE ReleaseHandle
		*  This uses CloseHandle to release a handle of any type.  I didn't expose it,
		*  mostly so that people wouldn't accidentally mash up things they shouldn't when
		*  experimenting
		LPARAMETER nHandleToRelease
		LOCAL nResult
		*	Use CloseHandle(), returns a BOOL;  0 = False
		DECLARE SHORT CloseHandle IN Win32API AS CloseHand INTEGER nHandleToClose
		IF TYPE('nHandleToRelease') = 'N' AND ! ISNULL(nHandleToRelease)
			nResult = CloseHand(nHandleToRelease)
			this.icErrorMessage = IIF(nResult = 0, 'CloseHandle() failed to close handle '+STR(nHandleToRelease),'')
		ELSE
			this.icErrorMessage = 'Invalid handle passed to ReleaseHandle() invocation'
			nResult = 0
		ENDIF
		RETURN (nResult = 1)
	ENDPROC


	PROCEDURE GetProcHandle
		*	Hand back the process handle in case someone needs it
		RETURN this.inProcessHandle
	ENDPROC


	PROCEDURE KillProc
		*  A wrapper on TerminateProcess(), it will terminate the process owned by
		*  the object unless you pass it another Process Handle.  If it's already dead,
		*  nohing interesting happens
		*
		*  TerminateProcess() does not shut down in an orderly fashion;  this is for emergencies!
		LPARAMETER nProcessToKill
		IF TYPE('nProcessToKill') # 'N'
			nProcessToKill = This.inProcessHandle
		ENDIF
		DECLARE SHORT TerminateProcess IN WIN32API AS KillProc ;
			INTEGER hProcess, ;
			INTEGER uExitCode
		LOCAL nResult
		IF ! ISNULL(nProcessToKill)
			nResult = KillProc(nProcessToKill,0)
			this.icErrorMessage = IIF(nResult = 0, 'TerminateProcess() could not kill process handle '+STR(nProcesToKill),'')
		ELSE
			this.icErrorMessage = 'NULL handle passed to KillProc()'
			nResult = 0
		ENDIF
		RETURN (nResult = 1)
	ENDPROC


	PROTECTED PROCEDURE ParsePROCESSINFOStruc
		*	Pull the Process and thread handles out of the PROCESSINFO structure
		LPARAMETER cProcessInfoStructure
		WITH This
			.inProcessHandle = .ExtractDWORD(cProcessInfoStructure)
			.inThreadHandle = .ExtractDWORD(SUBST(cProcessInfoStructure,5))
		ENDWITH

	ENDPROC


	PROCEDURE ExtractDWORD
		*  Convert a 4 byte string to an unsigned long (DWORD)
		LPARAMETER cStringToExtractFrom
		IF TYPE('cStringToExtractFrom')='C' AND LEN(cStringToExtractFrom) >= 4
			RETURN (((ASC(SUBST(cStringToExtractFrom,4,1))*256) + ;
									ASC(SUBST(cStringToExtractFrom,3,1)))*256 + ;
									ASC(SUBST(cStringToExtractFrom,2,1)))*256 + ;
									ASC(LEFT(cStringToExtractFrom,1))
		ELSE
			this.icErrorMessage = 'Invalid DWORD string passed for conversion'
			RETURN NULL
		ENDIF
	ENDPROC


	PROCEDURE Destroy
		*  Mommy, mommy make it go away!
		WITH THIS
			IF TYPE('.inThreadHandle') = 'N' AND NOT ISNULL(.inThreadHandle)
				*  If we still hold it, dispose the Thread handle
				.ReleaseHandle(.inThreadHandle)
				.inThreadHandle = NULL
			ENDIF
			IF TYPE('.inProcessHandle') = 'N' AND NOT ISNULL(.inProcessHandle)
				*  If we still hold it, dispose the Process handle
				.ReleaseHandle(.inProcessHandle)
				.inProcessHandle = NULL
			ENDIF
			*	NB - the process and thread object hang around until all handles to them are
			*	disposed by CloseHandle - going out of scope doesn't release them.
		ENDWITH
		DODEFAULT()
	ENDPROC


	PROCEDURE Init
		*
		*	API_AppRun - use the CreateProcess() API to launch, monitor, and kill an Executable
		*
		*	Properties:
		*
		*	inProcessHandle			(P)	ProcessHandle generated by CreateProcess()
		*	inThreadHandle			(P) ThreadHandle for First Thread of inProcessHandle
		*	icErrorMessage			R/O Error Message Detailed Description
		*	icCommandLine			R/W Command Line to launch via CreateProcess()
		*	icLaunchDir				R/W Directory to use as startup dir for CreateProcess()
		*	icWindowMode			R/W Window Start Mode, one of (HID, NOR, MIN, MAX) or empty
		*							defaults to empty, the default for the executable is used
		*
		*	Methods:
		*
		*	Init					(O) Command Line, (O) Start Dir, (O) Window Start Mode
		*							If sent, the icCommandLine, icLaunchDir and icWindowMode properties are set
		*	Destroy
		*	LaunchApp				// Launches .icComandLine from .icLaunchDir in .icWindowMode
		*							// NB - at least .icCommandLine must be set to not fail
		*							RETURNS: BOOL, check icErrorMessage on .F.
		*	LaunchAppAndWait		// Call LaunchApp() and wait on either user termination or process termination
		*							RETURNS: BOOL, check icErrorMessage on .F.
		*	CheckProcessExitCode	(O) Process handle to check, defaults to .inProcessHandle
		*							// Get Process named by Process Handle's Exit Code (259 = still running)
		*							RETURNS:  Integer, check on NULL, if NULL, check icErrorMessage
		*	ExtractDWORD			(R) String to convert
		*							//Converts a 4 byte or longer string to a DWORD integer
		*							RETURNS:  Integer, check on NULL, if NULL arg was invalid
		*	KillProc				(O) Process handle to Terminate, defaults to .inProcessHandle
		*							// Kills specified process using TerminateProcess()
		*							RETURNS:  BOOL, check icErrorMessage on .F.
		*	GetProcHandle			//  Returns the Process Handle for the current Process
		*							// NB - only useful for KillProc(), since Destroy will close the handle
		*							RETURNS:  Integer, check for NULL, if NULL no process was started yet
		*	ParsePROCESSINFOStruc	// Pulls the Process Handle and Thread Handle from the PROCESSINFO structure
		*							// Only used internally
		*	ReleaseHandle			(R)  Handle to Close
		*							//  Invokes CloseHandle() to explicitly release process/thread handles
		*							//  Only used internally, but can be externalized
		*							RETURNS:  BOOL, check .icErrorMessage on .F.
		*
		LPARAMETERS tcCommandLine, tcLaunchDir, tcWindowMode
		*	Set up the environment for the object
		LOCAL aDirTest[1,5]
		WITH THIS
			.icErrorMessage = ''
			.icCommandLine = ''
			.icLaunchDir = ''
			.icWindowMode = ''
			.inProcessHandle = NULL
			.inThreadHandle = NULL
			* store parameters if passed
			IF TYPE('tcCommandLine') = 'C'
				.icCommandLine = ALLTRIM(tcCommandLine)
			ENDIF
			DO CASE
			CASE TYPE('tcLaunchDir') # 'C'
				*	Not a character expression - ignore
			CASE ADIR(aDirTest, tcLaunchDir, 'D') # 1
				*	Either directory doesn't exist, or there's a wildcard in the expression
				.icErrorMessage = 'Invalid directory for startup passed to Init method'
			OTHERWISE
				*	Valid directory - save it
				.icLaunchDir = ALLTRIM(tcLaunchDir)
			ENDCASE
			DO CASE
			CASE TYPE('tcWindowMode') # 'C'
				*	Not passed in or not valid type
			CASE INLIST(PADR(UPPER(ALLTRIM(tcWindowMode)),3),'NOR','MIN','MAX','HID')
				*	Valid mode - set it
				.icWindowMode = PADR(UPPER(ALLTRIM(tcWindowMode)),3)
			OTHERWISE
				*	No a valid character string
				IF ! EMPTY(.icErrorMessage)
					.icErrorMessage = .icErrorMessage + ' &' + CHR(13) + CHR(10)
				ENDIF
				.icErrorMessage = .icErrorMessage + 'Invalid WindowMode passed to Init Method'
			ENDCASE
		ENDWITH
		RETURN .T.
	ENDPROC


ENDDEFINE
*
*-- EndDefine: api_apprun
**************************************************

<b>A simple set of examples on using the class...
we'll assume that the class code is in a procedure file
named <i>PROCESS.PRG</i></b>

SET PROCEDURE TO Process ADDITIVE
oProcess = CREATEOBJ('API_AppRun','NOTEPAD.EXE AUTOEXEC.BAT','C:\','NOR')
*Run the application and don't wait to terminate
oProcess.LaunchApp()
*Check the exit status;  259 means still running
IF oProcess.CheckProcessExitCode() = 259
	wait window 'Still running'
ELSE
	wait window 'Terminated with a '+alltrim(str(oProcess.CheckProcessExitCode()))
ENDIF
? oProcess.KillProc()
oProcess = ''
*  You can have multiple processes running at once
oProcess1 = CREATEOBJ('API_AppRun','REGEDIT','C:\','NOR')
oProcess2 = CREATEOBJ('API_AppRun','NET USE /? | MORE')
oProcess1.LaunchApp()
oProcess2.LaunchApp()
oProcess1 = ''
oProcess2 = ''
* Run them both and wait on the last to terminate
oProcess1 = CREATEOBJ('API_AppRun','NOTEPAD.EXE AUTOEXEC.BA','C:\','NOR')
oProcess2 = CREATEOBJ('API_AppRun','NOTEPAD.EXE CONFIG.SY','C:\','MIN')
oProcess1.LaunchApp()
oProcess2.LaunchAppAndWait()

Borislav Borissov
 

Hi Borislav

Calling DOS apps using CreateProcess brings the ugly black
screen. Which is definitely undesired. What parameter
suppresses it? WinExec suppresses it, but gives control back to VFP even before finishing it's work.

Thanks

Benson
 
I like the ShellExecute command. Use with the ,2) to not show the dos window. I pause to allow to run, then test for files to make sure ran later. On my XP computer the Dos Window closed no problems. On 98SE, I chose Properties CLOSE ON EXIT flagged. This created a "taxrates.pif" for the file i was trying to run. Now with this PIF to CLOSE ON EXIT, it always closes on XP and 98SE computers.

cfileexe= Fullpath( Curdir() ) + "taxrates.exe"
cAction = "open"
lResult = ShellExecute(0,cAction,cfileexe,"","",2)
=Inkey(.02)
Flush


 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top