> Hello All!
>
> I need to interface a VFP6.0 program with a FW2.6 program. I'm using RUN right now, but I've seen the posts where that isn't a good idea. I agree, because we sometimes get "WinExec Failed, Code=24" on some W2K computers. In fact, we can have the program run fine for a while, but once we get the error, it seems to be "broke" forever.
>
>
PUBLIC gcSYSMemFile, gcPath
> STORE FILENAME(M.SY_TempDir + "\" + SYS(3) + ".TMP") TO gcSYSMemFile
> SAVE ALL LIKE SY_* TO (M.gcSYSMemFile)
> STORE "F:" + M.gcSYSMemFile TO gcSYSMemFile
> STORE "P:" + SET("PATH") TO gcPath
> STORE FULLPATH("VISVF2FW.EXE") TO gcEXE
> STORE STUFF(M.gcEXE, AT(".EXE", M.gcExe), 4, "") TO gcExe
>
> And the actual run command is:
>
RUN /N &gcEXE &gcSYSMemFile &gcPath "R:VRR001.EXE" -T
>
> Any suggestions on how to "fix" the WinExec error? And any suggestions on the "best" way to do what I want? (Okay, besides converting all the FPW2.6 code to VFP... we're working on that! This is just a workaround until that is completed.)
>
> Cheryl A Bellucci
> TRIAD GOVERNMENTAL SYSTEMS, INC
> (who now uses her Foxite lunchbox to carry lunch to work!)
I have a little program that uses the CreateProcess API call to launch a program. Here is a snippet of the main functions:
FUNCTION NewLaunch()
LPARAMETERS tcFile, tlWaitForIt
* To run Notepad, you'd do the following
* NewLaunch("NOTEPAD.EXE C:\TEMP\TEXTFILE.TXT",.F.)
LOCAL cFile, nProcHand, llSuccess
llSuccess = .F.
tlWaitForIt = IIF(EMPTY(tlWaitForIt), .F., .T.)
nProcHand = NULL
cFile = tcFile
IF NOT LaunchApp(cFile,'','NOR', @nProcHand)
* Failed to run!
ELSE
llSuccess = .T.
DECLARE INTEGER Sleep IN WIN32API ;
INTEGER nMilliseconds
* To check on your instance later:
DO WHILE NOT ISNULL(nProcHand)
nResult = CheckProcessExitCode(nProcHand)
DO CASE
CASE ISNULL(nResult)
* Process is no longer in the system process table, so it isn't running
nProcHand = .NULL.
CASE nResult = 259
* Still running
IF M.tlWaitForIt
=Sleep(200)
ELSE
nProcHand = .NULL.
ENDIF
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(nProcHand)
nProcHand = .NULL.
ENDCASE
ENDDO
ENDIF
RETURN M.llSuccess
ENDFUNC
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
ENDFUNC
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)
ENDFUNC
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))
ENDFUNC
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
ENDFUNC
Lou Harris
lharris@epiqsystems.comSoftware Engineer, EPIQ Systems, Inc.
http://www.epiqsystems.com