Well this little project of mine has grown. The code's pretty long now, so it's available as a download. More macros available -
[See full code at end of post]
${ProcessExists}
Determines if a given process exists by name or PID, and returns the Process ID (PID).
${GetProcessPath}
Determines first if a process exists, and returns the full path by name or PID.
WARNING: This will only succeed if the calling process has sufficient rights to open the target process.
${GetProcessParent}
If the process exists, returns the parent process's PID.
${GetProcessName}
If the process exists, returns the name.
${EnumProcessPaths}
Passes all running process' full path and PID to a user defined function (works like the GetDrives macro).
WARNING: This will only succeed if the calling process has sufficient rights to open the target process.
${ProcessWait}
Will pause script execution until the given process exists or until timeout, by name. Will poll for the process every 500ms. Returns the process's PID, or -1 if timed out.
WARNING: this function is mildly CPU intensive, approx 2-10%. Be absolutely sure to include some value for RequestExecutionLevel
. Omitting it will more than double CPU usage for this command on Windows Vista+.
${ProcessWait2}
Same as ${ProcessWait}, but requires the FindProcDLL plugin, polls every 250ms, and is slightly less CPU intensive.
${ProcessWaitClose}
Will pause script execution until the given process no longer exists, by name or PID. Can specify a timeout value (how long to wait), or wait indefinitely. Returns the PID of the closing process if successful, -1 if timed out.
${CloseProcess}
Closes a process by name or PID by sending the WM_CLOSE message to all windows owned by the process. This is the MS recommended method for closing a process. It will give you the opportunity, for example, to save an unsaved txt file open in notepad. This command will return immediately after sending the messages, so it's advisable to check when the process actually closes, ie with ${ProcessWaitClose}. Returns the closed process's PID.
${TerminateProcess}
Forcibly closes a process by name or PID. Returns the terminated process's PID.
${Execute}
Runs a process, supports commandline arguments. Allows you to optionally specify a working directory and returns the process's PID if successful, 0 if it fails.
Full code embedded:
/* _____________________________________________________________________________ Process Functions Header v2.2 _____________________________________________________________________________ 2008-2010 Erik Pilsits aka wraithdu License: zlib/libpng See documentation for more information about the following functions. Usage in script: 1. !include "ProcFunc.nsh" 2. [Section|Function] ${ProcFunction} "Param1" "Param2" "..." $var [SectionEnd|FunctionEnd] ProcFunction=[GetProcessPID|GetProcessPath|GetProcessParent|GetProcessName| EnumProcessPaths|ProcessWait|ProcessWait2|ProcessWaitClose| CloseProcess|TerminateProcess|Execute] There is also a LogicLib extension: ${If} ${ProcessExists} file.exe ... ${EndIf} _____________________________________________________________________________ Thanks to: _____________________________________________________________________________ Some functions based on work by Donald Miller and Phoenix1701@gmail.com _____________________________________________________________________________ Individual documentation: _____________________________________________________________________________ ${ProcessExists} "[process]" "[process]" ; Name or PID Use with a LogicLib conditional command like If or Unless. Evaluates to true if the process exists or false if it does not or the CreateToolhelp32Snapshot fails. ${GetProcessPID} "[process]" $var "[process]" ; Name or PID $var(output) ; -2 - CreateToolhelp32Snapshot failed ; 0 - process does not exist ; >0 - PID ${GetProcessPath} "[process]" $var "[process]" ; Name or PID $var(output) ; -2 - CreateToolhelp32Snapshot failed ; -1 - OpenProcess failed ; 0 - process does not exist ; Or path to process ${GetProcessParent} "[process]" $var "[process]" ; Name or PID $var(output) ; -2 - CreateToolhelp32Snapshot failed ; 0 - process does not exist ; Or PPID ${GetProcessName} "[PID]" $var "[PID]" ; PID $var(output) ; -2 - CreateToolhelp32Snapshot failed ; 0 - process does not exist ; Or process name ${EnumProcessPaths} "Function" $var "Function" ; Callback function $var(output) ; -2 - EnumProcesses failed ; 1 - success Function "Function" Pop $var1 ; matching path string Pop $var2 ; matching process PID ...user commands Push [1/0] ; must return 1 on the stack to continue ; must return some value or corrupt the stack ; DO NOT save data in $0-$9 FunctionEnd ${ProcessWait} "[process]" "[timeout]" $var "[process]" ; Name "[timeout]" ; -1 - do not timeout ; >0 - timeout in milliseconds $var(output) ; -2 - CreateToolhelp32Snapshot failed ; -1 - operation timed out ; Or PID ${ProcessWait2} "[process]" "[timeout]" $var "[process]" ; Name "[timeout]" ; -1 - do not timeout ; >0 - timeout in milliseconds $var(output) ; -1 - operation timed out ; Or PID ${ProcessWaitClose} "[process]" "[timeout]" $var "[process]" ; Name "[timeout]" ; -1 - do not timeout ; >0 - timeout in milliseconds $var(output) ; -1 - operation timed out ; 0 - process does not exist ; Or PID of ended process ${CloseProcess} "[process]" $var "[process]" ; Name or PID $var(output) ; 0 - process does not exist ; Or PID of ended process ${TerminateProcess} "[process]" $var "[process]" ; Name or PID $var(output) ; -1 - operation failed ; 0 - process does not exist ; Or PID of ended process ${Execute} "[command]" "[working_dir]" $var "[command]" ; '"X:\path\to\prog.exe" arg1 arg2 "arg3 with space"' "[working_dir]" ; Working directory ("X:\path\to\dir") or nothing ("") $var(output) ; 0 - failed to create process ; Or PID */ ;_____________________________________________________________________________ ; ; Macros ;_____________________________________________________________________________ ; ; Change log window verbosity (default: 3=no script) ; ; Example: ; !include "ProcFunc.nsh" ; ${PROCFUNC_VERBOSE} 4 # all verbosity ; ${PROCFUNC_VERBOSE} 3 # no script !ifndef PROCFUNC_INCLUDED !define PROCFUNC_INCLUDED !include Util.nsh !include LogicLib.nsh !verbose push !verbose 3 !ifndef _PROCFUNC_VERBOSE !define _PROCFUNC_VERBOSE 3 !endif !verbose ${_PROCFUNC_VERBOSE} !define PROCFUNC_VERBOSE `!insertmacro PROCFUNC_VERBOSE` !verbose pop !macro PROCFUNC_VERBOSE _VERBOSE !verbose push !verbose 3 !undef _PROCFUNC_VERBOSE !define _PROCFUNC_VERBOSE ${_VERBOSE} !verbose pop !macroend !define PROCESS_QUERY_INFORMATION 0x0400 !define PROCESS_TERMINATE 0x0001 !define PROCESS_VM_READ 0x0010 !define SYNCHRONIZE 0x00100000 !define WAIT_TIMEOUT 0x00000102 !ifdef NSIS_UNICODE !define _PROCFUNC_WSTRING "&w260" !else !define _PROCFUNC_WSTRING "&w520" !endif !macro ProcessExists !error "ProcessExists has been renamed to GetProcessPID" !macroend !macro _ProcessExists _a _b _t _f !insertmacro _LOGICLIB_TEMP !verbose push !verbose ${_PROCFUNC_VERBOSE} Push `${_b}` ${CallArtificialFunction} LLProcessExists_ IntCmp $_LOGICLIB_TEMP 0 `${_f}` Goto `${_t}` !verbose pop !macroend !define ProcessExists `"" ProcessExists` !macro GetProcessPID !macroend !define GetProcessPID "!insertmacro GetProcessPIDCall" !macro GetProcessPIDCall process outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push 0 Push `${process}` !ifdef CallArtificialFunction_TYPE ; macro nesting disallowed, breaks otherwise if used from WaitClose ${CallArtificialFunction2} ProcFuncs_ !else ${CallArtificialFunction} ProcFuncs_ !endif Pop ${outVar} !verbose pop !macroend !macro GetProcessPath !macroend !define GetProcessPath "!insertmacro GetProcessPathCall" !macro GetProcessPathCall process outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push 1 Push `${process}` ${CallArtificialFunction} ProcFuncs_ Pop ${outVar} !verbose pop !macroend !macro GetProcessParent !macroend !define GetProcessParent "!insertmacro GetProcessParentCall" !macro GetProcessParentCall process outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push 2 Push `${process}` ${CallArtificialFunction} ProcFuncs_ Pop ${outVar} !verbose pop !macroend !macro GetProcessName !macroend !define GetProcessName "!insertmacro GetProcessNameCall" !macro GetProcessNameCall process outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push 6 Push `${process}` ${CallArtificialFunction} ProcFuncs_ Pop ${outVar} !verbose pop !macroend !macro EnumProcessPaths !macroend !define EnumProcessPaths "!insertmacro EnumProcessPathsCall" !macro EnumProcessPathsCall user_func outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push $0 GetFunctionAddress $0 `${user_func}` Push `$0` ${CallArtificialFunction} EnumProcessPaths_ Exch Pop $0 Pop ${outVar} !verbose pop !macroend !macro ProcessWait !macroend !define ProcessWait "!insertmacro ProcessWaitCall" !macro ProcessWaitCall process timeout outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push `${timeout}` Push `${process}` ${CallArtificialFunction} ProcessWait_ Pop ${outVar} !verbose pop !macroend !macro ProcessWait2 !macroend !define ProcessWait2 "!insertmacro ProcessWait2Call" !macro ProcessWait2Call process timeout outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push `${timeout}` Push `${process}` ${CallArtificialFunction} ProcessWait2_ Pop ${outVar} !verbose pop !macroend !macro ProcessWaitClose !macroend !define ProcessWaitClose "!insertmacro ProcessWaitCloseCall" !macro ProcessWaitCloseCall process timeout outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push `${timeout}` Push `${process}` ${CallArtificialFunction} ProcessWaitClose_ Pop ${outVar} !verbose pop !macroend !macro CloseProcess !macroend !define CloseProcess "!insertmacro CloseProcessCall" !macro CloseProcessCall process outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push `${process}` ${CallArtificialFunction} CloseProcess_ Pop ${outVar} !verbose pop !macroend !macro TerminateProcess !macroend !define TerminateProcess "!insertmacro TerminateProcessCall" !macro TerminateProcessCall process outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push `${process}` ${CallArtificialFunction} TerminateProcess_ Pop ${outVar} !verbose pop !macroend !macro Execute !macroend !define Execute "!insertmacro ExecuteCall" !macro ExecuteCall cmdline wrkdir outVar !verbose push !verbose ${_PROCFUNC_VERBOSE} Push `${wrkdir}` Push `${cmdline}` ${CallArtificialFunction} Execute_ Pop ${outVar} !verbose pop !macroend !macro ProcFuncs_ System::Store "s" ; store registers in System's private stack Pop $0 ; process / PID Pop $1 ; mode Push 0 ; set return value if not found ; set mode of operation in $1 ${Select} $1 ; mode 0 = GetProcessPID, mode 1 = GetProcessPath, mode 2 = GetProcessParent ${Case} 0 StrCpy $2 $0 4 -4 ${If} $2 == ".exe" ; exists from process name StrCpy $1 0 ${Else} ; exists from pid StrCpy $1 1 ${EndIf} ${Case} 1 StrCpy $2 $0 4 -4 ${If} $2 == ".exe" ; get path from process name StrCpy $1 2 ${Else} ; get path from pid StrCpy $1 3 ${EndIf} ${Case} 2 StrCpy $2 $0 4 -4 ${If} $2 == ".exe" ; get parent from process name StrCpy $1 4 ${Else} ; get parent from pid StrCpy $1 5 ${EndIf} ${EndSelect} System::Call '*(&l4,i,i,i,i,i,i,i,i,${_PROCFUNC_WSTRING})i .r2' ; $2 = PROCESSENTRY32W structure ; take system process snapshot in $3 System::Call 'kernel32::CreateToolhelp32Snapshot(i 2, i 0)i .r3' ${Unless} $3 = -1 System::Call 'kernel32::Process32FirstW(i r3, i r2)i .r4' ${Unless} $4 = 0 ${Do} ${Select} $1 ${Case3} 0 2 4 ; get process name in $5 System::Call '*$2(i,i,i,i,i,i,i,i,i,${_PROCFUNC_WSTRING} .r5)' ${Case4} 1 3 5 6 ; get process PID in $5 System::Call '*$2(i,i,i .r5)' ${EndSelect} ; is this process the one we are looking for? ${If} $5 == $0 ; string test works ok for numeric PIDs as well ${Select} $1 ; mode 0/1 = GetProcessPID, mode 2/3 = GetProcessPath, mode 4/5 = GetProcessParent, mode 6 = GetProcessName ${Case2} 0 1 ; return pid Pop $5 ; old return value System::Call '*$2(i,i,i .s)'; process pid to stack ${Case2} 2 3 ; return full path Pop $5 ; open process System::Call '*$2(i,i,i .s)'; process pid to stack System::Call 'kernel32::OpenProcess(i ${PROCESS_QUERY_INFORMATION}|${PROCESS_VM_READ}, i 0, i s)i .r5' ; process handle to $5 ${Unless} $5 = 0 ; full path to stack System::Call 'psapi::GetModuleFileNameExW(i r5, i 0, w .s, i ${NSIS_MAX_STRLEN})' System::Call 'kernel32::CloseHandle(i r5)' ${Else} Push -1 ; OpenProcess failure return value ${EndUnless} ${Case2} 4 5 ; return parent PID Pop $5 System::Call '*$2(i,i,i,i,i,i,i .s)'; parent pid to stack ${Case} 6 ; return base name Pop $5 System::Call '*$2(i,i,i,i,i,i,i,i,i,${_PROCFUNC_WSTRING} .s)' ${EndSelect} ${Break} ${EndIf} System::Call 'kernel32::Process32NextW(i r3, i r2)i .r4' ${LoopUntil} $4 = 0 System::Call 'kernel32::CloseHandle(i r3)' ; close snapshot ${EndUnless} ${Else} Pop $5 Push -2 ; function failure return value ${EndUnless} System::Free $2 ; free buffer System::Store "l" ; restore registers !macroend !macro EnumProcessPaths_ System::Store "s" ; store registers in System's private stack Pop $0 ; user_func StrCpy $1 1 ; OK to loop System::Alloc 1024 Pop $2 ; process list buffer ; get an array of all process ids System::Call 'psapi::EnumProcesses(i r2, i 1024, *i .r3)i .r4' ; $3 = sizeof buffer ${Unless} $4 = 0 IntOp $3 $3 / 4 ; Divide by sizeof(DWORD) to get $3 process count IntOp $3 $3 - 1 ; decrement for 0 base loop ${For} $4 0 $3 ${IfThen} $1 != 1 ${|} ${Break} ${|} ; get a PID from the array IntOp $5 $4 * 4 ; calculate offset IntOp $5 $5 + $2 ; add offset to original buffer address System::Call '*$5(i .r5)' ; get next PID = $5 ${Unless} $5 = 0 System::Call 'kernel32::OpenProcess(i ${PROCESS_QUERY_INFORMATION}|${PROCESS_VM_READ}, i 0, i r5)i .r6' ${Unless} $6 = 0 ; $6 is hProcess ; get full path System::Call 'psapi::GetModuleFileNameExW(i r6, i 0, w .r7, i ${NSIS_MAX_STRLEN})i .r8' ; $7 = path ${Unless} $8 = 0 ; no path System::Store "s" ; store registers in System's private stack Push $5 ; PID to stack Push $7 ; path to stack Call $0 ; user func must return 1 on the stack to continue looping System::Store "l" ; restore registers Pop $1 ; continue? ${EndUnless} System::Call 'kernel32::CloseHandle(i r6)' ${EndUnless} ${EndUnless} ${Next} Push 1 ; return value ${Else} Push -2 ; function failure return value ${EndUnless} System::Free $2 ; free buffer System::Store "l" ; restore registers !macroend !macro ProcessWait_ System::Store "s" ; store registers in System's private stack Pop $0 ; process Pop $1 ; timeout StrCpy $6 1 ; initialize loop StrCpy $7 0 ; initialize timeout counter System::Call '*(&l4,i,i,i,i,i,i,i,i,${_PROCFUNC_WSTRING})i .r2' ; $2 = PROCESSENTRY32W structure ${DoWhile} $6 = 1 ; processwait loop ; take system process snapshot in $3 System::Call 'kernel32::CreateToolhelp32Snapshot(i 2, i 0)i .r3' ${Unless} $3 = -1 System::Call 'kernel32::Process32FirstW(i r3, i r2)i .r4' ${Unless} $4 = 0 ${Do} ; get process name in $5 System::Call '*$2(i,i,i,i,i,i,i,i,i,${_PROCFUNC_WSTRING} .r5)' ${If} $5 == $0 ; exists, return pid System::Call '*$2(i,i,i .s)'; process pid to stack ; process pid StrCpy $6 0 ; end loop ${Break} ${EndIf} System::Call 'kernel32::Process32NextW(i r3, i r2)i .r4' ${LoopUntil} $4 = 0 System::Call 'kernel32::CloseHandle(i r3)' ; close snapshot ${EndUnless} ${Else} Push -2 ${Break} ${EndUnless} ; timeout loop ${If} $6 = 1 ${If} $1 >= 0 IntOp $7 $7 + 500 ; increment timeout counter ${AndIf} $7 >= $1 ; timed out, break loop Push -1 ; timeout return value ${Break} ; end loop if timeout ${EndIf} Sleep 500 ; pause before looping ${EndIf} ${Loop} ; processwaitloop System::Free $2 ; free buffer System::Store "l" ; restore registers !macroend !macro ProcessWait2_ System::Store "s" ; store registers in System's private stack System::Store "P0" ; FindProcDLL return value Pop $0 ; process Pop $1 ; timeout StrCpy $2 0 ; initialize timeout counter ${Do} FindProcDLL::FindProc $0 ${IfThen} $R0 = 1 ${|} ${Break} ${|} ${If} $1 >= 0 IntOp $2 $2 + 250 ${AndIf} $2 >= $1 Push -1 ; timeout return value ${Break} ${EndIf} Sleep 250 ${Loop} ${If} $R0 = 1 ; success, get pid ${GetProcessPID} $0 $0 Push $0 ; return pid ${EndIf} System::Store "R0" ; restore registers System::Store "l" !macroend !macro ProcessWaitClose_ System::Store "s" ; store registers in System's private stack Pop $0 ; process / PID Pop $1 ; timeout ; passed process name or pid StrCpy $2 $0 4 -4 ${If} $2 == ".exe" ${GetProcessPID} $0 $0 ${EndIf} ; else passed pid directly ${Unless} $0 = 0 System::Call 'kernel32::OpenProcess(i ${SYNCHRONIZE}, i 0, i r0)i .r2' ${Unless} $2 = 0 ; $2 is hProcess System::Call 'kernel32::WaitForSingleObject(i r2, i $1)i .r1' ${If} $1 = ${WAIT_TIMEOUT} Push -1 ; timed out ${Else} Push $0 ; return pid of ended process ${EndIf} System::Call 'kernel32::CloseHandle(i r2)' ${Else} Push 0 ; failure return value ${EndUnless} ${Else} Push 0 ; failure return value ${EndUnless} System::Store "l" ; restore registers !macroend !macro CloseProcess_ System::Store "s" ; store registers in System's private stack Pop $0 ; process / PID ; passed process name or pid StrCpy $1 $0 4 -4 ${If} $1 == ".exe" ${GetProcessPID} $0 $0 ${EndIf} ; else passed pid directly ${Unless} $0 = 0 ; $0 = target pid Push $0 ; return pid of process ; use EnumWindows and a callback System::Get '(i .r1, i)i sr4' ; $1 = hwnd, $4 = callback#, s (stack) = source for return value Pop $3 ; $3 = callback address System::Call 'user32::EnumWindows(k r3, i)i' ; enumerate top-level windows ${DoWhile} $4 == "callback1" System::Call 'user32::GetWindowThreadProcessId(i r1, *i .r2)i' ; $2 = pid that created the window ${If} $2 = $0 ; match to target pid SendMessage $1 16 0 0 /TIMEOUT=1 ; send WM_CLOSE to all top-level windows owned by process, timeout immediately ${EndIf} Push 1 ; callback return value; keep enumerating windows (returning 0 stops) StrCpy $4 "" ; clear callback# System::Call '$3' ; return from callback ${Loop} System::Free $3 ; free callback ${Else} Push 0 ; failure return value ${EndUnless} System::Store "l" ; restore registers !macroend !macro TerminateProcess_ System::Store "s" ; store registers in System's private stack Pop $0 ; process / PID ; passed process name or pid StrCpy $1 $0 4 -4 ${If} $1 == ".exe" ${GetProcessPID} $0 $0 ${EndIf} ; else passed pid directly ${Unless} $0 = 0 System::Call 'kernel32::OpenProcess(i ${PROCESS_TERMINATE}, i 0, i r0)i .r1' ${Unless} $1 = 0 ; $1 is hProcess System::Call 'kernel32::TerminateProcess(i r1, i 0)i .r1' ${If} $1 = 0 ; fail Push -1 ${Else} Push $0 ; return pid of ended process ${EndIf} System::Call 'kernel32::CloseHandle(i r1)' ${Else} Push 0 ; failure return value ${EndUnless} ${Else} Push 0 ; failure return value ${EndUnless} System::Store "l" ; restore registers !macroend !macro Execute_ System::Store "s" ; store registers in System's private stack Pop $0 ; cmdline Pop $1 ; wrkdir System::Alloc 68 ; 4*16 + 2*2 / STARTUPINFO structure = $2 Pop $2 System::Call '*$2(i 68)' ; set cb = sizeof(STARTUPINFO) System::Call '*(i,i,i,i)i .r3' ; PROCESS_INFORMATION structure = $3 ${If} $1 == "" StrCpy $1 "i" ${Else} StrCpy $1 'w "$1"' ${EndIf} System::Call `kernel32::CreateProcessW(i, w '$0', i, i, i 0, i 0, i, $1, i r2, i r3)i .r4` ; return 0 if fail ${Unless} $4 = 0 ; failed to create process System::Call '*$3(i .r4, i .r5, i .r6)' ; read handles and PID System::Call 'kernel32::CloseHandle(i $4)' ; close hProcess System::Call 'kernel32::CloseHandle(i $5)' ; close hThread Push $6 ; return PID ${Else} Push 0 ; return val if failed ${EndUnless} System::Free $2 ; free STARTUPINFO struct System::Free $3 ; free PROCESS_INFORMATION struct System::Store "l" ; restore registers !macroend !macro LLProcessExists_ System::Store "s" ; store registers in System's private stack Pop $0 ; process name StrCpy $_LOGICLIB_TEMP 0 System::Call '*(&l4,i,i,i,i,i,i,i,i,${_PROCFUNC_WSTRING})i .r2' ; $2 = PROCESSENTRY32W structure ; take system process snapshot in $3 System::Call 'kernel32::CreateToolhelp32Snapshot(i 2, i 0)i .r3' IntCmp $3 -1 done System::Call 'kernel32::Process32FirstW(i r3, i r2)i .r4' IntCmp $4 0 endloop loop: System::Call '*$2(i,i,i,i,i,i,i,i,i,${_PROCFUNC_WSTRING} .r5)' StrCmp $5 $0 0 next_process StrCpy $_LOGICLIB_TEMP 1 Goto endloop next_process: System::Call 'kernel32::Process32NextW(i r3, i r2)i .r4' IntCmp $4 0 endloop Goto loop endloop: System::Call 'kernel32::CloseHandle(i r3)' ; close snapshot done: System::Free $2 ; free buffer System::Store "l" ; restore registers !macroend !endif ; PROCFUNC_INCLUDED /**************************************************************************** Functions ========= HANDLE WINAPI OpenProcess( __in DWORD dwDesiredAccess, __in BOOL bInheritHandle, __in DWORD dwProcessId ); BOOL WINAPI CreateProcess( __in_opt LPCTSTR lpApplicationName, __inout_opt LPTSTR lpCommandLine, __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, __in BOOL bInheritHandles, __in DWORD dwCreationFlags, __in_opt LPVOID lpEnvironment, __in_opt LPCTSTR lpCurrentDirectory, __in LPSTARTUPINFO lpStartupInfo, __out LPPROCESS_INFORMATION lpProcessInformation ); typedef struct _STARTUPINFO { DWORD cb; LPTSTR lpReserved; LPTSTR lpDesktop; LPTSTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; DWORD dwYSize; DWORD dwXCountChars; DWORD dwYCountChars; DWORD dwFillAttribute; DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; LPBYTE lpReserved2; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; } STARTUPINFO, *LPSTARTUPINFO; typedef struct _PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION, *LPPROCESS_INFORMATION; BOOL WINAPI EnumProcesses( __out DWORD* pProcessIds, __in DWORD cb, __out DWORD* pBytesReturned ); DWORD WINAPI GetModuleBaseName( __in HANDLE hProcess, __in_opt HMODULE hModule, __out LPTSTR lpBaseName, __in DWORD nSize ); DWORD WINAPI GetModuleFileNameEx( __in HANDLE hProcess, __in_opt HMODULE hModule, __out LPTSTR lpFilename, __in DWORD nSize ); BOOL WINAPI CloseHandle( __in HANDLE hObject ); DWORD WINAPI WaitForSingleObject( __in HANDLE hHandle, __in DWORD dwMilliseconds ); BOOL WINAPI TerminateProcess( __in HANDLE hProcess, __in UINT uExitCode ); BOOL EnumWindows( __in WNDENUMPROC lpEnumFunc, __in LPARAM lParam ); DWORD GetWindowThreadProcessId( __in HWND hWnd, __out LPDWORD lpdwProcessId ); BOOL PostMessage( __in HWND hWnd, __in UINT Msg, __in WPARAM wParam, __in LPARAM lParam ); ****************************************************************************/