ShellExecEx: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
 
(7 intermediate revisions by 2 users not shown)
Line 3: Line 3:


== Description ==
== Description ==
Executes files via the ShellExecuteEx api, uses three modes: 1. nowait, returns process id, 2. nowait, returns process handle, and 3. wait mode, returns process exit code. WinXP.SP1/Win2003 or higher is required for mode 1.
Executes files via the ShellExecuteEx api, uses three modes: 1. nowait - returns process id, 2. nowait - returns process handle, and 3. wait mode - returns process exit code. XP-SP1/2003 or higher is required for mode 1.




Line 10: Line 10:
<highlight-nsis>
<highlight-nsis>
!define IfProcExistsH "!insertmacro _IfProcExistsH"  
!define IfProcExistsH "!insertmacro _IfProcExistsH"  
!macro _IfProcExistsH _ProcHandle_ _GotoIfTrue_ _GotoIfFalse_  
!macro _IfProcExistsH _ProcHandle_ _GotoIfTrue_ _GotoIfFalse_ ;; gotos: no negative numbers, use labels instead
   Push "$0"  
   Push "$0"  
   ClearErrors  
   ClearErrors  
   System::Call 'kernel32::WaitForSingleObject(i ${_ProcHandle_}, i 0) i .r0'  
   System::Call 'kernel32::WaitForSingleObject(i ${_ProcHandle_}, i 0) i .r0' ;; no wait, just check if ok
   IntCmp $0 0 +2  
   IntCmp $0 0 +2  
       SetErrors  
       SetErrors  
Line 32: Line 32:
<highlight-nsis>
<highlight-nsis>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Gets the parent folder
;; Gets the parent directory
;; P1 :out: Folder containing file or dir (parent folder)
;; P1 :out: Parent dir
;; P2 :in:  File/Dir
;; P2 :in:  File/Dir
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Line 62: Line 62:
;; Executes a file with the ShellExecuteEx api
;; Executes a file with the ShellExecuteEx api
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; P1 :out: Return value, depends on the mode (P5). On error returns 0 and sets the error flag
;; P1 :out: Return value, depends on the mode (P7). On error returns -1 and sets the error flag
;; P2 :in:  Verb. if="" then it opens with default associated app
;; P2 :in:  Verb. if="" then it opens with default associated app
;; P3 :in:  File
;; P3 :in:  File
Line 70: Line 70:
;; P7 :in:  Mode: 1=Nowait, Return Process Id
;; P7 :in:  Mode: 1=Nowait, Return Process Id
;;                2=Nowait, Return Process Handle (must close the handle yourself)
;;                2=Nowait, Return Process Handle (must close the handle yourself)
;;                3=Wait, Return Exit Code
;;                3=Wait, Return Process Exit Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
!define ShellExecEx "!insertmacro _ShellExecEx"
!define ShellExecEx "!insertmacro _ShellExecEx"
Line 88: Line 88:
   Exch $1  ;; File
   Exch $1  ;; File
   Exch 2
   Exch 2
   Exch $2  ;; Params
   Exch $2  ;; Params / process handle
   Exch 3
   Exch 3
   Exch $3  ;; WorkDir
   Exch $3  ;; WorkDir
   Exch 4
   Exch 4
   Exch $4  ;; Show
   Exch $4  ;; Show / return value
   Exch 5
   Exch 5
   Exch $5  ;; Mode
   Exch $5  ;; Mode
   Push "$9"  ;; shellexecuteinfo struct
   Push "$9"  ;; shellexecuteinfo struct
    
    
  ClearErrors
   StrCmpS "" "$3" 0 wdok
   StrCmpS "" "$3" 0 wdok
       ${PathPath} $3 "$1"
       ${PathPath} $3 "$1"
Line 106: Line 107:
   System::Call 'shell32::ShellExecuteEx(i r9) i .r1'  ;; execute the file
   System::Call 'shell32::ShellExecuteEx(i r9) i .r1'  ;; execute the file
   StrCmpS 0 $1 0 +4  ;; if there was errors, then
   StrCmpS 0 $1 0 +4  ;; if there was errors, then
       StrCpy $3 0 ; set return value to 0 and set the error flag
       StrCpy $4 -1 ; return -1 and set the error flag
       SetErrors
       SetErrors
       Goto end
       Goto end
Line 119: Line 120:
       Goto end
       Goto end
;      wait:
;      wait:
       System::Call 'kernel32::WaitForSingleObject(i r2, i -1)'
       System::Call 'kernel32::WaitForSingleObject(i r2, i -1)' ;;  wait indefinitely for the process to exit
       System::Call 'kernel32::GetExitCodeProcess(i r2,*i .r4)'
       System::Call 'kernel32::GetExitCodeProcess(i r2,*i .r4)'
       System::Call 'Kernel32::CloseHandle(i r2)'
       System::Call 'Kernel32::CloseHandle(i r2)'

Latest revision as of 12:26, 3 December 2011

Author: Lloigor (talk, contrib)


Description

Executes files via the ShellExecuteEx api, uses three modes: 1. nowait - returns process id, 2. nowait - returns process handle, and 3. wait mode - returns process exit code. XP-SP1/2003 or higher is required for mode 1.


Example

Tests if a process, identified by a handle, still exists.

!define IfProcExistsH "!insertmacro _IfProcExistsH" 
!macro _IfProcExistsH _ProcHandle_ _GotoIfTrue_ _GotoIfFalse_  ;; gotos: no negative numbers, use labels instead
   Push "$0" 
   ClearErrors 
   System::Call 'kernel32::WaitForSingleObject(i ${_ProcHandle_}, i 0) i .r0' ;; no wait, just check if ok
   IntCmp $0 0 +2 
      SetErrors 
   Pop $0 
   IfErrors ${_GotoIfTrue_} ${_GotoIfFalse_} 
!macroend  
 
${ShellExecEx} $0 '' '"$EXEDIR\test.exe"' '' '' '' 2
loop: 
/* some code here */ 
${IfProcExistsH} $0 0 +3 
   MessageBox MB_OK "The process still exists." 
   Goto loop 
MessageBox MB_OK "The process doesn't exists anymore!"

Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Gets the parent directory
;; P1 :out: Parent dir
;; P2 :in:  File/Dir
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
!define PathPath "!insertmacro _PathPath"
!macro _PathPath _RetVal_ _Path_
   Push "${_Path_}"
   Call PathPath
   Pop "${_RetVal_}"
!macroend
Function PathPath
   Exch $0  ;; Path
   Push $1  ;; Strlen / Counter
   Push $2  ;; Curchar
   StrLen $1 '$0'
   IntCmp $1 0 +6
      IntOp $1 $1 - 1
      StrCpy $2 "$0" 1 $1
      StrCmp "$2" '\' +3
      StrCmp "$2" ":" 0 -4
         IntOp $1 $1 + 1
   StrCpy $0 "$0" $1 0
   Pop $2
   Pop $1
   Exch $0
FunctionEnd
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Executes a file with the ShellExecuteEx api
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; P1 :out: Return value, depends on the mode (P7). On error returns -1 and sets the error flag
;; P2 :in:  Verb. if="" then it opens with default associated app
;; P3 :in:  File
;; P4 :in:  File parameters
;; P5 :in:  Working directory. if="" then its set to the same dir as the file
;; P6 :in:  Show flag. if="" then SH_SHOW is used (http://msdn.microsoft.com/en-us/library/bb762153(v=VS.85).aspx)
;; P7 :in:  Mode: 1=Nowait, Return Process Id
;;                2=Nowait, Return Process Handle (must close the handle yourself)
;;                3=Wait, Return Process Exit Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
!define ShellExecEx "!insertmacro _ShellExecEx"
!macro _ShellExecEx _RetVal_ _Verb_ _File_ _Params_ _WorkDir_ _Show_ _Mode_  
   Push `${_Mode_}`
   Push `${_Show_}`
   Push `${_WorkDir_}`
   Push `${_Params_}`
   Push `${_File_}`
   Push `${_Verb_}`
   Call ShellExecEx
   Pop ${_RetVal_}
!macroend
Function ShellExecEx
   Exch $0  ;; Verb
   Exch
   Exch $1  ;; File
   Exch 2
   Exch $2  ;; Params / process handle
   Exch 3
   Exch $3  ;; WorkDir
   Exch 4
   Exch $4  ;; Show / return value
   Exch 5
   Exch $5  ;; Mode
   Push "$9"  ;; shellexecuteinfo struct
 
   ClearErrors
   StrCmpS "" "$3" 0 wdok
      ${PathPath} $3 "$1"
   wdok:
   StrCmpS "" "$4" 0 +2  ;; if show mode is undefined, then
      StrCpy $4 0x05    ; = SH_SHOW
   System::Call '*(&i60) i .r9' ;; allocate the structure
   System::Call '*$9(i 60, i 0x140, i $HWNDPARENT, t r0, t r1, t r2, t r3, i r4) i .r9'  ;; assign the values to the struct
   System::Call 'shell32::ShellExecuteEx(i r9) i .r1'  ;; execute the file
   StrCmpS 0 $1 0 +4  ;; if there was errors, then
      StrCpy $4 -1  ; return -1 and set the error flag
      SetErrors
      Goto end
 
   System::Call '*$9(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i .r2)'  ;; get the process handle
   IntCmp $5 2 +4 0 +6  ;; 1:nowait-pid, 2:nowait-handle, 3:wait-exitcode
      System::Call 'kernel32::GetProcessId(i r2) i .r4'
      System::Call 'kernel32::CloseHandle(i r2)'
      Goto end
;      handle:
      StrCpy $4 "$2"
      Goto end
;      wait:
      System::Call 'kernel32::WaitForSingleObject(i r2, i -1)'  ;;  wait indefinitely for the process to exit
      System::Call 'kernel32::GetExitCodeProcess(i r2,*i .r4)'
      System::Call 'Kernel32::CloseHandle(i r2)'
 
   end:
   System::Free $9
   Pop $9
   Pop $5
   Pop $0
   Pop $1
   Pop $2
   Pop $3
   Exch $4
FunctionEnd