// StartProg.pkg // Author: Bernhard Ponemayr // Date: 03.07.2002 // // replacement for the runprogram command of vdf // // Syntax: // Get gStartProgram Command Parameters Directory WindowVisible WaitUntilFinished to ReturnValue // // Parameters: // Command: is the Program to Run (with or without path) // Parameters: the Parameters given to the Program // Directory: the Working Directory of the Program (if blank, the current directory of vdf is used) // WindowVisible: TRUE if a resulting window is initially visible (may be changed by the program itself) // WaitUntilFinished: TRUE if the function should wait until the started program is finished // // returns: // -1 If the programm could Not be started // ProcessID if the programm was started and the WaitUntilFinished Parameter was FALSE // ExitCode of the started program if the programm was started and the WaitUntilFinished Parameter was TRUE // // Example: // Get gStartProgram "calc.exe" "" "" TRUE FALSE to iRetVal // Starts the Windows Calculator and returns the ProcessID of calc.exe if successfully or -1 // // Changelog: // 07.03.2013 BP: Double Quotes are no added before and after the Commandline to Support // long Paths with Blanks inside Define STARTF_USESHOWWINDOW FOR |CI$00000001 Define STARTF_USESIZE FOR |CI$00000002 Define STARTF_USEPOSITION FOR |CI$00000004 Define STARTF_USECOUNTCHARS FOR |CI$00000008 Define STARTF_USEFILLATTRIBUTE FOR |CI$00000010 Define STARTF_RUNFULLSCREEN FOR |CI$00000020 // ignored for non-x86 platforms Define STARTF_FORCEONFEEDBACK FOR |CI$00000040 Define STARTF_FORCEOFFFEEDBACK FOR |CI$00000080 Define STARTF_USESTDHANDLES FOR |CI$00000100 Define STARTF_USEHOTKEY FOR |CI$00000200 Define STILL_ACTIVE FOR 259 TYPE STARTUPINFO Field STARTUPINFO.cb as DWORD Field STARTUPINFO.lpReserved as Pointer Field STARTUPINFO.lpDesktop as Pointer Field STARTUPINFO.lpTitle as Pointer Field STARTUPINFO.dwX as DWORD Field STARTUPINFO.dwY as DWORD Field STARTUPINFO.dwXSize as DWORD Field STARTUPINFO.dwYSize as DWORD Field STARTUPINFO.dwXCountChars as DWORD Field STARTUPINFO.dwYCountChars as DWORD Field STARTUPINFO.dwFillAttribute as DWORD Field STARTUPINFO.dwFlags as DWORD Field STARTUPINFO.wShowWindow as WORD Field STARTUPINFO.cbReserved2 as WORD Field STARTUPINFO.lpReserved2 as Pointer Field STARTUPINFO.hStdInput as Handle Field STARTUPINFO.hStdOutput as Handle Field STARTUPINFO.hStdError as Handle END_TYPE TYPE PROCESSINFO Field PROCESSINFO.hProcess as Handle Field PROCESSINFO.hThread as Handle Field PROCESSINFO.dwProcessId as DWORD Field PROCESSINFO.dwThreadId as DWORD END_TYPE external_function CreateProcessEf "CreateProcessA" kernel32.dll Pointer pName Pointer pCmdL Pointer lpPAttr Pointer lpTAttr Integer bInherit Integer dwCrFlag Pointer pEnv Pointer lpCurDir Pointer lpStartup Pointer lpProcInfo Returns Integer external_function GetExitCodeProcessEf "GetExitCodeProcess" kernel32.dll Handle hProcess Pointer lpExitCode Returns Integer external_function CloseHandleEf "CloseHandle" kernel32.dll Handle hHandle Returns Integer external_function SleepEf "Sleep" kernel32.dll Integer iMilliSeconds Returns Integer #IFNDEF get_GetLastError external_function GetLastError "GetLastError" kernel32.dll Returns Integer #ENDIF Function gStartProgram GLOBAL String sCommand String sParams String sDir Integer bVisible Integer bWaitForFinished Returns Integer String sCmd sPara sWorkDir sStartup sProcessInfo sExitCode Pointer pCmd pPara pWorkDir pStartup pProcessInfo pExitCode Integer iRet iError iID iExitCode Handle hProcess hThread // Change 9th of March, 2013 Bernhard Ponemayr // In some rare cases the sCommand needs to surrounded by quotes for the CreateProcess function // to work properly. If (Left(sCommand, 1) <> '"' and (Left(sCommand, 1) <> "'")) Begin Move ('"' + sCommand + '"') to sCommand // Add double Quotes to the Command if needed End Move (sCommand + " " + sParams + (Character(0))) to sCmd // Take Program and CmdLines Move (sDir + (Character(0))) to sWorkDir getaddress of sCmd to pCmd getaddress of sWorkDir to pWorkDir Move (OemToAnsi(pCmd,pCmd)) to iRet // Convert to ANSI Move (OemToAnsi(pWorkDir,pWorkDir)) to iRet If ( ((Trim(sDir)) = "") or ((Trim(sDir)) = ".") ) Move 0 to pWorkDir // If the Directory is empty or . use the current threads directory zerotype STARTUPINFO to sStartup zerotype PROCESSINFO to sProcessInfo put STARTUPINFO_SIZE to sStartup at STARTUPINFO.cb put STARTF_USESHOWWINDOW to sStartup at STARTUPINFO.dwFlags If (bVisible) put SW_SHOW to sStartup at STARTUPINFO.wShowWindow // Make the window visible or not Else put SW_HIDE to sStartup at STARTUPINFO.wShowWindow getaddress Of sStartup to pStartup getaddress Of sProcessInfo to pProcessInfo Move (CreateProcessEf(0,pCmd,0,0,FALSE,0,0,pWorkDir,pStartup,pProcessInfo)) to iRet // Create the process Move (GetLastError()) to iError If iRet Eq 0 Function_Return -1 // if creation failed return -1 getbuff From sProcessInfo at PROCESSINFO.hProcess to hProcess // Take the Process and Thread handles getbuff From sProcessInfo at PROCESSINFO.hThread to hThread If bWaitForFinished Begin // Wait for the process finished zerostring 32 to sExitCode getaddress Of sExitCode to pExitCode Move (GetExitCodeProcessEf(hProcess,pExitCode)) to iRet // Get the Process Exit Code If iRet Eq 0 Begin // Return 0 if the Exit Code could not be retrieved If hProcess Move (CloseHandleEf(hProcess)) to iRet // Take care to Destroy the Handles If hThread Move (CloseHandleEf(hThread)) to iRet Function_Return 0 End Move (BytesToDword(sExitCode,1)) to iExitCode While iExitCode Eq STILL_ACTIVE // Loop as long the Exit code is STILL_ACTIVE Move (SleepEf(100)) to iRet // Very interesting how much faster the program is executed by this line :-) zerostring 32 to sExitCode getaddress Of sExitCode to pExitCode Move (GetExitCodeProcessEf(hProcess,pExitCode)) to iRet // All the same as above If iRet Eq 0 Begin If hProcess Move (CloseHandleEf(hProcess)) to iRet If hThread Move (CloseHandleEf(hThread)) to iRet Function_Return 0 End Move (BytesToDword(sExitCode,1)) to iExitCode End If hProcess Move (CloseHandleEf(hProcess)) to iRet // Destroy the handles If hThread Move (CloseHandleEf(hThread)) to iRet Function_Return iExitCode // Return the delivered exit-code End getbuff From sProcessInfo at PROCESSINFO.dwProcessID to iID // if not waiting return the delivered process-id If hProcess Move (CloseHandleEf(hProcess)) to iRet // Destroy the handles If hThread Move (CloseHandleEf(hThread)) to iRet Function_Return iID End_Function