问题
When downloading the .exe installation file (NSIS installation) and opening it via chrome in order to execute it the ExecWait dosen't work.
I'm running a batch file which kill browsers processes inside of the installation, because I opened the exe file via the chrome (Download Manager) the ExecWait think that the execute has ended and therefore dosen't wait for the next ExecWait calls that coming after the line which call to execute the batch file. It think that chrome was the parent process so it quitting the installation.
Is there a way to let the ExecWait know that although I killed the chrome browser (or any other browsers) process to continue the installation? and waiting for only the .exe files that I execute via the NSIS script?
P.S - When installing the .exe file out of the browser (download manager) it works fine.
EDIT (I HAVE INCLUDED CODES):
# define the name of the installer
outfile "setup.exe"
Name "Example"
installDir $LOCALAPPDATA\Test
# default section
section
setOutPath $INSTDIR
File install.exe
File test.exe
ExecWait $INSTDIR\install.exe
Delete $INSTDIR\install.exe
ExecWait $INSTDIR\test.exe
Delete $INSTDIR\test.exe
sectionEnd
and inside of the install.exe (its a .bat file the I compile to an .exe file) this code:
@echo off
taskkill /F /IM chrome.exe /T
If you download the setup.exe via chrome and executing it from the bottom bar (download manager) it will execute install.exe (closing chrome.exe) but will skip this lines:
Delete $INSTDIR\install.exe
ExecWait $INSTDIR\test.exe
Delete $INSTDIR\test.exe
回答1:
ExecWait always waits for the child process it started but it does not wait for grandchildren. If you need to do that you can try this macro.
IMHO killing a browser like this is not cool (What if they are doing something important in a tab?), you should just ask the user to close it.
回答2:
Have you tried calling directly to taskkill?
Execwait '"$SYSDIR\taskkill.exe" /F /IM chrome.exe /T'
回答3:
So, if I understand correctly:
Chrome --> downloaded_setup.exe --> install.exe --> force kill chrome w/ child processes
So to answer to you question: no there is no mean to make the setup started by Chrome resist to a force kill (it is actually killed because of the /T
parameter that kills the whole process subtree with child processes). You are just cutting the branch you are standing in :)
If you do need to kill Chrome, I would suggest to try to spawn a second copy of downloaded_setup.exe
from itself but detached from calling process (see CreateProcess flags).
In the second instance of the setup, you can check if you are the second process by testing its parent (process name of parent pid would be chrome or not) with the get process info macros.
EDIT: i wrongly interpreted the meaning of the DETACHED_PROCESS
flag for CreateProcess
: its usage is for console programs, to not make them use the console inherited by their parent.
Actually, to make a process detached from its parent A, the only way is to start a process B that will start a process C and quit the process B. Then the process C is no more descendant of A and if you kill A, C will stay alive.
For the fun of proff of concept, here is a NSIS script that will respawn itself if started by Chrome. If you look at the processes with ProcessExplorer or ProcessHacker when the messagebox shows, you will see that the visible setup is not child of chrome... Thanks to Anders that helped me to debug the call to CreateProcess
:)
!include "TextFunc.nsh"
!include "logiclib.nsh"
!include "getprocessinfo.nsh"
outfile "parent.exe"
!define DEBUG `System::Call kernel32::OutputDebugString(ts)`
!define PARENT "chrome.exe"
Var cmd
Section
; Do your stuff here
; ...
SectionEnd
Function .onInit
${GetProcessInfo} 0 $0 $1 $2 $3 $4 ;info for current process pid
${GetProcessInfo} $1 $0 $1 $2 $3 $5 ;get parent process info
${if} $3 == ${PARENT}
StrCpy $cmd '"$EXEDIR\$EXEFILE"'
System::Alloc 68 ;// $1 = buffer for struct STARTUPINFO
Pop $1
System::Call "*$1(i 68)" ;// StartUp.cb=sizeof(STARTUPINFO);
System::Alloc 16 ;// $2 = buffer for struct PROCESS_INFORMATION
Pop $2
System::Call 'kernel32::CreateProcess(i0,t $cmd,i0,i0,i0,i0,i0,i0,ir1,ir2)i.r0' ;re-spawn ourselve
System::Free $1
${if} $0 <> 0
System::Call "*$2(i.r3,i.r4,i.r5,i.r6) ?!e"
;${debug} "PHND=$3 PID=$5"
System::Call 'kernel32::CloseHandle(i $3)'
System::Call 'kernel32::CloseHandle(i $4)'
${endif}
System::Free $2
Quit
${endif}
Sleep 500 ;wait to have time for parent process to quit
MessageBox MB_OK "My parent is not ${PARENT}"
FunctionEnd
来源:https://stackoverflow.com/questions/13933469/nsis-execwait-dosent-wait-when-installing-the-setup-file-via-chrome-browser