>David,
>
>I pciked this up off of UT, it is not my work and I don't have the name of the original author. I wish I did. I believe I found it in the files section here on UT. I've played around with it and it seems to work.
>
That's one of mine; I've been playing around with a few refinements. The code here was posted in a FAQ a week or so ago.
There are a few improvements in the works; the PROCESSINFO structure contains both a ProcessHandle and a ThreadHandle that ought to be released explicily with CloseHandle() to avoid memory bleeds caused by keeping process and thread objects floating around; not much of an issue unless you have a very minimal memory configuration and run CreateProcess() a whole lot. (Win32 keeps process and thread objects open as long as there are unreleased handles; even if they go out of scope and drop from memory the reference count is not decremented unless CloseHandle() is called.)
I'll probably be releasing an API-based process class once I finish playing around with some added functionality (do things like check termination status and properly release any handles when the VFP object is released.)
>I don't think the code pasted to well. I'll see if I can send it as an email.
>
>
>The following code will launch a DOS or Windows executable without using the RUN command; it gives some control over the starting window of the executable, and waits pretty reliably on termination, using the Process Handle rather than a Window Handle to test for completion. My thanks to dozens of instances of various applets like NOTEPAD and EDLIN, without whom this code would never have been debugged:
>FUNCTION LaunchAppAndWait
>LPARAMETERS tcCommandLine, tuFromDir, tcWindowMode
>
>* tcCommandLine (R) - command line to launch
>* tuFromDir (O) - Run from directory (default - CWD)
>* tcWindowMode (O) - Start Application Window mode, one of (HIDE, MIN, MAX, NOR)
>* (default - default setting of application)
>
>* Returns:
>* 0 = CreateProcess didn't start what was asked
>* 1 = Process ran to completion
>* -1= Process started but user aborted wait. Danger - app is still running AFAIK
>
>#DEFINE cnINFINITE 0xFFFFFFFF
>#DEFINE cnHalfASecond 500 && milliseconds
>#DEFINE cnTimedOut 0x0102
>
>* We need some API calls, declare here
>
>* GetCurrentProcess() returns the pseudohandle of the current process
>DECLARE INTEGER GetCurrentProcess IN WIN32API AS GetCurrProc
>
>* WaitForIdleInput() waits until the target process is idle for input
>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
>
>* 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 to us
>* 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 us, 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 on return
>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
>
>IF TYPE('tcCommandLine') # 'C'
>
> * Command line must be a character string
> RETURN 0
>
>ENDIF
>IF TYPE('tuFromDir') # 'C'
>
> * If not a character string, pass a null pointer, defaulting to Current Working Dir
> tuFromDir = 0
>
>ELSE
>
> * Otherwise, null pad the string
> tuFromDir = tuFromDir + CHR(0)
>
>ENDIF
>IF TYPE('tcWindowMode') # 'C'
>
> * If not passed, set to null string
> tcWindowMode = ''
>
>ELSE
>
> * Translate the passed window mode to uppercase
> tcWindowMode = UPPER(tcWindowMode)
>
>ENDIF
>
>LOCAL nStartedProcessHandle, uResult, 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 tcWindowMode = 'HIDE'
>
> * Hide - use STARTF_USESHOWFLAG and value of 0
> cStartUpInfo = CHR(68) + ;
> REPL(CHR(0),43) + ;
> CHR(1) + ;
> REPL(CHR(0),23)
>
>CASE tcWindowMode = '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 tcWindowMode = '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 tcWindowMode = '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)
>
>* Other options exist - see WINBASE.H for values
>
>OTHERWISE
>
> * Use default of application
> cStartUpInfo = CHR(68) + REPL(CHR(0),67)
>
>ENDCASE
>
>* Do it now!
>uResult = CrPr( 0, ;
> tcCommandLine, ;
> 0, 0, 0, 0, 0, ;
> tuFromDir, ;
> @cStartUpInfo, ;
> @cProcessInfo)
>
>IF uResult = 1
>
> * CreateProcess() started our app, but we have to wait until it finishes loading
>
> * Strip the process handle from the PROCESS_INFORMATION structure
>
> nStartedProcessHandle = (((ASC(SUBST(cProcessInfo,4,1))*256) + ;
> ASC(SUBST(cProcessInfo,3,1)))*256 + ;
> ASC(SUBST(cProcessInfo,2,1)))*256 + ;
> ASC(LEFT(cProcessInfo,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(nStartedProcessHandle, cnHalfASecond) = cnTimedOut
>
> * Give us an out in case the other app hangs - lets the user quit via
> IF INKEY() = 27
> * Still running but we aren't waiting - return a -1 as a warning
> uResult = -1
> EXIT
> ENDIF
>
> ENDDO
>
>ELSE
>
> * Return 0 to indicate failure
> uResult = 0
>
>ENDIF
>RETURN uResult
>
>
>
>>I remember seeing a technique for doing a RUN command without seeing the DOS window pop up.
>>I want to synchronise a client pc to the NT server using
>>
run /n net time \\server /yes
>>but not see the box.
>>BTW, is there another way of doing this seemlessly?
>>TIA