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