Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Is an app running?
Message
General information
Forum:
Visual FoxPro
Category:
Other
Miscellaneous
Thread ID:
00160151
Message ID:
00160277
Views:
19
>Hi -
>
>I am working on a VFP5 project that uses an EXE written in Visual Dialog Script (sim to VB I think....). Per Dragan's suggestion, I store this EXE in the memo field of a VFP table, and then copy it out to the hard drive to run it. This particular EXE could take a few hours to run, so I need to figure out the best way to get rid of it when it has finished running. I am thinking of checking (and erasing if it exists and isn't running) this in 3 places... when the user closes the form that created it, when they close the application and when they open the application.
>
>I am pretty satisfied w/this method, but the question is what is the BEST way to check to see if the application is still running? I've thought of a few kludges (try to delete it, and trap the error or have the external app write a .txt file to the hard drive when it is finished), but I know there must be a better way. I'm thinking this has something to do with the Windows API. Am I on the right track?
>

It depends on whether your application is starting it or not. if your application launches the other executable, the single most positive method of identifying whether an application is running would be to query its exit status. In order to do this, you need a process handle. fortunately, if you launch the application yourself, it's very easy to get!

The CreateProcess() API call will run an application for you. It provides considerably capability; if you can launch something with the VFP RUN command, you can use CreateProcess() to execute it. A sample of how You would use it follows:
FUNCTION LaunchApp
LPARAMETERS cCommandLine, uFromDir, cWindowMode, nReturnProcessHandle
cCommandLine = ALLTRIM(cCommandLine)
IF TYPE('uFromDir') # 'C' OR EMPTY(uFromDir)
		*	If not a character string, pass a null pointer, defaulting to Current Working Dir
		uFromDir = 0
ELSE
		*	Otherwise, null pad the string
		uFromDir = uFromDir + CHR(0)
ENDIF
IF TYPE('cWindowMode') # 'C'
		*	If not passed, set to null string
		cWindowMode = ''
ELSE
		*	Translate the passed window mode to uppercase
		cWindowMode = UPPER(cWindowMode)
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
	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()

	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
	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
		nReturnProcessHandle = ParseProcessInfoStruc(cProcessInfo)
		RETURN .T.
	ELSE
		RETURN .F.
	ENDIF

FUNCTION ParseProcessInfoStruc
LPARAMETER cProcessInfoStructure
LOCAL nHandle
*  Throw away the thread handle, we don't need it, and it eats an entry in the system
*  object table until you close the handle
DECLARE SHORT CloseHandle IN Win32API AS CloseHand INTEGER nHandleToClose
=CloseHand(ExtractDWORD(SUBST(cProcessInfoStructure,5)))
RETURN ExtractDWORD(cProcessInfoStructure)

FUNCTION ExtractDWORD
LPARAMETER cStringToExtractFrom
RETURN (((ASC(SUBST(cStringToExtractFrom,4,1))*256) + ;
			ASC(SUBST(cStringToExtractFrom,3,1)))*256 + ;
			ASC(SUBST(cStringToExtractFrom,2,1)))*256 + ;
			ASC(LEFT(cStringToExtractFrom,1))

FUNCTION CheckProcessExitCode
LPARAMETER nProcessToCheck
IF TYPE('nProcessToCheck') # 'N'
	RETURN NULL
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
		RETURN NULL
	ENDIF
ELSE
	RETURN NULL
ENDIF

To run Notepad maximized , you'd do the following

nProcHand = NULL
= LaunchApp('NOTEPAD.EXE C:\SomeDir\SomeFile.TXT','','MAX',@nProcHand)

To check on your instance of Notepad later:

nResult = CheckProcessExitCode(nProchand)
DO CASE
CASE ISNULL(nResult)
   *  Process is no longer in the system process table, so it isn't running
CASE nResult = 259
   *  Still running
OTHERWISE
   *  It's no longer running, and terminated with the exit code value in nResult
   *  You should release the handle now to release the process object from system memory
   * by calling CloseHandle() like this
   * DECLARE SHORT CloseHandle IN Win32API AS CloseHand INTEGER nHandleToClose
    * =CloseHand(nResult)
ENCASE
EMail: EdR@edrauh.com
"See, the sun is going down..."
"No, the horizon is moving up!"
- Firesign Theater


NT and Win2K FAQ .. cWashington WSH/ADSI/WMI site
MS WSH site ........... WSH FAQ Site
Wrox Press .............. Win32 Scripting Journal
eSolutions Services, LLC

The Surgeon General has determined that prolonged exposure to the Windows Script Host may be addictive to laboratory mice and codemonkeys
Previous
Reply
Map
View

Click here to load this message in the networking platform