Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Complex forms software to replace Delrina FF
Message
From
23/11/2004 12:39:27
 
 
To
23/11/2004 12:19:11
General information
Forum:
Visual FoxPro
Category:
Other
Miscellaneous
Thread ID:
00931761
Message ID:
00963924
Views:
45
This works (small mods):
*SET PROCEDURE TO <tempfile>
=RunExeAndWait("C:\Windows\Notepad.exe")


PROCEDURE  RunExeAndWait
* procedure to fire up an external program and suspend all VFP activities until it closes

* Written by: Albert Gostick
* Last Updated: Nov 23, 2004

* Parameters:
* tcExeName: application (exe or com etc) to fire up (file name and path only - no parameters for app); e.g.
*    c:\VFP\Test\TestApp.exe
* tcCommandLine: full command line including parameters with a space between exe and parameters; full path to
*    exe should be wrapped in quotes if there is a space anywhere in the file path
* tcStartupDir: startup directory for the process (optional)

* Note: that none of the above parameters need to be null terminated as this character will be added below

LPARAMETERS tcExeName, tcCommandLine, tcStartupDir

LOCAL llOldAutoYield, llReturn, ;
      ;
      lcNullChar, lcStartupInfo, lcProcessInfo, lnPriority, lnInheritHandles, lnExitCode, lnResult, ;
      lnProcessHandle, lnThreadHandle

* use this over and over so stuff in var
STORE CHR(0) TO lcNullChar

*** Parameter checks ***
* all parameters must be and null-terminated if passed and empty character if not passed

* tcExeName
IF VARTYPE(tcExeName) # "C"
   STORE "" TO tcExeName
ELSE
   IF NOT RIGHT(tcExeName,1) == lcNullChar
      STORE tcExeName + lcNullChar TO tcExeName
   ENDIF
ENDIF

* tcCommandLine
IF VARTYPE(tcCommandLine) # "C"
   STORE "" TO tcCommandLine
ELSE
   IF NOT RIGHT(tcCommandLine,1) == lcNullChar
      STORE tcCommandLine + lcNullChar TO tcCommandLine
   ENDIF
ENDIF

* tcStartupDir
IF VARTYPE(tcStartupDir) # "C"
   STORE "" TO tcStartupDir
ELSE
   IF NOT RIGHT(tcStartupDir,1) == lcNullChar
      STORE tcStartupDir + lcNullChar TO tcStartupDir
   ENDIF
ENDIF

* call function to set up DLL calls
DeclareDLLs()

* default return value (only set to .F. on error)
STORE .T. TO llReturn

* save autoyield setting to restore and then set for here
STORE _VFP.AutoYield TO llOldAutoYield
STORE .T. TO _VFP.AutoYield

*** Short Documentation On CreateProcess ***

* Parameters passed and what I have been able to figure out from various sources:

* [1] lcApplicationName: optional; if not passed, the information in parsed from Param 2, lcCommandLine; must
*     be null terminated
* [2] lcCommandLine: command line to run including any parameters to be passed to program; if param 1 is empty,
*     then param 2 must contain the file to run including path (e.g c:\Temp\Temp.exe) and this has to be
*     separated from the parameters with a space (eg. C:\Temp\Temp.exe <param>)
* [3] lcProcessAttributes: something to do with assigning security attributes to the process or allowing the
*     returned handle to be inherited by child processes; not sure what this means but we pass zero which
*     means they cannot be inherited (I think - null cannot be inherited so zero must be same as null)
* [4] lcThreadAttributes: sounds identical to [2] but applies to threads; zero passed so handle cannot be inherited
* [5] llInheritHandles: if TRUE (1?) then each inheritable handle in the calling process is inherited by the
*     new process; our sample was set to 1 (true I think)
* [6] lcCreationFlags: flags used when creating the process; in our case, flag is used to set priority for the
*     process so named lnPriority; value of 32 means "Normal" priority
* [7] lcEnvironment: if null, new process uses environment of the calling process (if used, seems to be a string of
*     environmental vars (eg. DEV=0N) that is passed to set up the environment; each set of vars is delimted by
*     the null character and then the entire block is terminated with a null as well
* [8] lcCurrentDirectory: directory to startup the process in (I think this is the same as the "Start-In" option'
*     on a shortcut; must be null-terminated; if not passed, the directory for the calling program is used; note that
*     in our sample this was not used but might be better than wrapping call to ExeWait in SET DEFAULT TO before
*     and after calling ExeWait()
* [9] lcStartupInfo: string that is filled with startup info that after the call will contain (according to the docs)
*     "window station, desktop, standard handles and appearance of main window for new process"; although this is
*     passed in to function here, it does not seem to be parsed after returning; the string "D" + 67 nulls are
*     passed in as the string to be filled; it looks like this string can be filled with values to set things like
*     window caption of new process, window height etc; do not have good example on how to use yet
* [10] lcProcessInfo: string that is filled with "process info" which I think is handles to the new process and it
*     thread; it is filled with 16 nulls and if the process is created correctly, then lcProcessInfo can be
*     parsed to obtain the following: handle to new process [chars 1 to 4], handle to thread [chars 5 to 8], 
*     number identifying process [chars 9 to 12 I think], number identifying new thread [chars 13 to 16 I thnk];
*     these seem to be "double word" values as they have to be converted using a function to convert from base
*     256 values (see function String2DWord())

* Returns: non-zero if process successfully created (TRUE) or zero if process creation failed (FALSE)

* set some values for CreateProcess
lnInheritHandles = 1
lnPriority = 32
lcStartupInfo = CHR(68) + REPLICATE(CHR(0),67)
lcProcessInfo = REPLICATE(CHR(0),16)

* init lnResult
STORE 0 TO lnResult

* create the process and capture the result
STORE CreateProcess(0,tcExeName+" "+tcCommandLine+CHR(0),0,0,;
	lnInheritHandles,lnPriority,;
	0,0,@lcStartupInfo,@lcProcessInfo) TO lnResult

* if non-zero returned, process was successfully created
IF lnResult = 0

   STORE GetLastError() TO lnErrorNum
   WAIT WINDOW "Last Error num: " + LTRIM(STR(lnErrorNum))

ELSE

   * string lcProcessInfo will now contain a series of handles in it; pull out 1st 4 chars as the process
   * handle and then the next 4 chars as the thread handle; these are in a base 256 format that need to
   * be coverted back to numeric (it seems)

   lnProcessHandle = String2dWord(SUBSTR(lcProcessInfo,1,4))
   lnThreadHandle = String2DWord(SUBSTR(lcProcessInfo,5,4))

   * wait until the termination of the program
   DOEVENTS

   DO WHILE .T.

      * reset exit code each loop
      STORE 0 TO ExitCode

      * fetch the exit code from the app
      =GetExitCodeProcess(lnProcessHandle,@ExitCode)

      * if exitcode = 259, this means app not busy so exit
      IF exitcode # 259  && not still busy
         EXIT
      ENDIF

      Sleep(100) && wait .1 seconds

   ENDDO

   CloseHandle(lnThreadHandle)
   CloseHandle(lnProcessHandle)

ENDIF

* restore autoyield setting if needed
IF llOldAutoYield = .F.
   STORE .F. TO VFP.AutoYield
ENDIF

* call function to release DLLs
ReleaseDLLs()

RETURN (llReturn)


* function to convert a string that is base 256 to it's numeric equivalent
* Written by: Albert Gostick
* Last Updated: Nov 22, 2004
PROCEDURE String2DWord
PARAMETERS tcString
RETURN ASC(SUBSTR(tcString,1,1)) + ;
   ASC(SUBSTR(tcString,2,1)) * 256 + ;
   ASC(SUBSTR(tcString,3,1)) * 65536 + ;
   ASC(SUBSTR(tcString,4,1)) * 16777216 
   TO lnReturn


PROCEDURE DeclareDLLS
* procedure to load required DLLs for above procs

* Written by: Albert Gostick
* Last Updated: Nov 23, 2004

LOCAL dllArray[1], lnNumDLLs

* grab list of DLL's
STORE ADLLS(dllarray) TO lnNumDLLs

IF ASCAN(dllarray,'CREATEPROCESS') = 0
    DECLARE INTEGER CreateProcess IN kernel32;
        INTEGER lpAppName, STRING lpCmdLine, INTEGER lpProcAttr,;
        INTEGER lpThrAttr, INTEGER bInhHandles, INTEGER dwCrFlags,;
        INTEGER lpEnvir, INTEGER lpCurDir, ;
        STRING @lpStInfo, STRING @lpProcInfo
ENDIF
IF ASCAN(dllarray,'GETLASTERROR') = 0
    DECLARE INTEGER GetLastError IN kernel32
ENDIF
IF ASCAN(dllarray,"CLOSEHANDLE") = 0
    DECLARE INTEGER CloseHandle IN kernel32 INTEGER hObject
ENDIF
IF ASCAN(dllarray,"GETEXITCODEPROCESS") = 0
    DECLARE INTEGER GetExitCodeProcess IN WIN32API INTEGER hProcess, INTEGER @lpExitCode
ENDIF
IF ASCAN(dllarray,"SLEEP") = 0
    DECLARE Sleep IN kernel32 INTEGER dwMilliseconds
ENDIF

RETURN

PROCEDURE ReleaseDLLs  && release dlls for exewait function

CLEAR DLLS CreateProcess
CLEAR DLLS GetLastError
CLEAR DLLS CloseHandle
CLEAR DLLS GetExitCodeProcess
CLEAR DLLS Sleep

RETURN
.·*´¨)
.·`TCH
(..·*

010000110101001101101000011000010111001001110000010011110111001001000010011101010111001101110100
"When the debate is lost, slander becomes the tool of the loser." - Socrates
Vita contingit, Vive cum eo. (Life Happens, Live With it.)
"Life is not measured by the number of breaths we take, but by the moments that take our breath away." -- author unknown
"De omnibus dubitandum"
Previous
Reply
Map
View

Click here to load this message in the networking platform