/*
_____________________________________________________________________________

                      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
	);

****************************************************************************/