*-------------------------------------------------------------------------------------------------------------------------------------------------------- * (EN) AUTOGENERATED - ATTENTION!! - NOT INTENDED FOR EXECUTION!! USE ONLY FOR MERGING CHANGES AND STORING WITH SCM TOOLS!! *-------------------------------------------------------------------------------------------------------------------------------------------------------- *< FOXBIN2PRG: Version="1.21" SourceFile="process.vcx" CPID="1252" /> (Solo para binarios VFP 9 / Only for VFP 9 binaries) * * DEFINE CLASS api_apprun AS custom *< CLASSDATA: Baseclass="custom" Timestamp="" Scale="Pixels" Uniqueid="" /> * *m: checkprocessexitcode *m: extractdword *m: getprochandle *m: killproc *m: launchapp *m: launchappandwait *m: parseprocessinfostruc *m: releasehandle *p: iccommandline *p: icerrormesage *p: icerrormessage *p: iclaunchdir *p: icwindowmode *p: inprocesshandle *p: inthreadhandle * PROTECTED inprocesshandle,inthreadhandle * iccommandline = space(0) icerrormesage = (space(0)) iclaunchdir = (space(0)) icwindowmode = (space(0)) inprocesshandle = .NULL. inthreadhandle = .NULL. Name = "api_apprun" * PROCEDURE checkprocessexitcode 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 PROCEDURE Destroy WITH THIS IF TYPE('.inThreadHandle') = 'N' AND NOT ISNULL(.inThreadHandle) .ReleaseHandle(.inThreadHandle) .inThreadHandle = NULL ENDIF IF TYPE('.inProcessHandle') = 'N' AND NOT ISNULL(.inProcessHandle) .ReleaseHandle(.inProcessHandle) .inProcessHandle = NULL ENDIF ENDWITH DODEFAULT() ENDPROC PROCEDURE extractdword 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 getprochandle RETURN this.inProcessHandle 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 if false * 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 + ' & ' ENDIF .icErrorMessage = .icErrorMessage + CHR(10) + CHR(13) + 'Invalid WindowMode passed to Init Method' ENDCASE ENDWITH RETURN .T. ENDPROC PROCEDURE killproc 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 requested','') ELSE this.icErrorMessage = 'NULL handle passed to KillProc()' nResult = 0 ENDIF RETURN (nResult = 1) ENDPROC PROCEDURE launchapp LOCAL cCommandLine, uFromDir, cWindowMode WITH This .icErrorMessage = '' IF TYPE('.icCommandLine') # 'C' * Command line must be a character string .icErrorMessage = 'icCommand line 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 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 - 4 bytes, a Process handle, a Thread Handle, a (DWORD) ProcessId and a (DWORD) ThreadID * we save the Process handle and return it to caller in tnReturnProcessHandle 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 .ParseProcessInfoStruc(cProcessInfo) RETURN .T. ELSE .icErrorMessage = 'Process Specified by icCommandLine could not be started' RETURN .F. ENDIF ENDWITH ENDPROC PROCEDURE launchappandwait #Define cnINFINITE 0xFFFFFFFF #Define cnHalfASecond 500 && milliseconds #Define cnTimedOut 258 && 0x0102 Local loEx As Exception * 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 Try * 01.10.2008 * nu stiu de ce da eroare la inkey() lnInkey = Inkey() *!* StrToFile('inkey: ' + Transform(lnInkey) + ' type: ' + Type('lnInkey'),"c:\inkey.txt") If lnInkey = 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 Catch To loEx * do nothing Endtry * 01.10.2008 ^ Enddo Else * Return 0 to indicate failure uResult = 0 Endif Endwith Return (uResult = 1) ENDPROC PROCEDURE parseprocessinfostruc LPARAMETER cProcessInfoStructure WITH This .inProcessHandle = .ExtractDWORD(cProcessInfoStructure) .inThreadHandle = .ExtractDWORD(SUBST(cProcessInfoStructure,5)) ENDWITH ENDPROC PROTECTED PROCEDURE releasehandle 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, 'TerminateProcess() failed to close handle','') ELSE this.icErrorMessage = 'Invalid handle passed to ReleaseHandle() invocation' nResult = 0 ENDIF RETURN (nResult = 1) ENDPROC ENDDEFINE