0

下载 .exe 安装文件(NSIS 安装)并通过 chrome 打开它以执行它时,ExecWait 不起作用。

我正在运行一个批处理文件,它会在安装过程中杀死浏览器进程,因为我通过 chrome(下载管理器)打开了 exe 文件,ExecWait 认为执行已经结束,因此不要等待下一个 ExecWait 调用即将到来在调用执行批处理文件的行之后。它认为 chrome 是父进程,所以它退出了安装。

有没有办法让 ExecWait 知道虽然我终止了 chrome 浏览器(或任何其他浏览器)进程以继续安装?只等待我通过 NSIS 脚本执行的 .exe 文件?

PS - 从浏览器(下载管理器)安装 .exe 文件时,它工作正常。

编辑(我已包含代码):

# 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

在 install.exe (它是一个 .bat 文件,我编译成一个 .exe 文件)内部,这段代码:

@echo off
taskkill /F /IM chrome.exe /T

如果您通过 chrome 下载 setup.exe 并从底部栏(下载管理器)执行它,它将执行 install.exe(关闭 chrome.exe)但会跳过以下行:

Delete $INSTDIR\install.exe
ExecWait $INSTDIR\test.exe
Delete $INSTDIR\test.exe
4

3 回答 3

1

ExecWait总是等待它启动的子进程,但它不等待孙子进程。如果你需要这样做,你可以试试这个宏

恕我直言,像这样杀死浏览器并不酷(如果他们在选项卡中做一些重要的事情怎么办?),您应该只要求用户关闭它。

于 2012-12-18T19:03:18.900 回答
1

您是否尝试过直接调用taskkill?

Execwait '"$SYSDIR\taskkill.exe" /F /IM chrome.exe /T'
于 2012-12-19T10:07:18.167 回答
0

所以,如果我理解正确:

Chrome --> downloaded_setup.exe --> install.exe --> force kill chrome w/ child processes

所以回答你的问题:不,没有办法让 Chrome 启动的设置抵抗强制终止(它实际上被杀死是因为/T参数会杀死带有子进程的整个进程子树)。你只是在剪掉你站在的树枝:)

如果您确实需要杀死 Chrome,我建议您尝试downloaded_setup.exe从自身生成第二个副本,但与调用进程分离(请参阅CreateProcess 标志)。

在设置的第二个实例中,您可以通过使用get process info macros测试其父进程(父 pid 的进程名称是否为 chrome)来检查您是否是第二个进程。


编辑:我错误地解释了DETACHED_PROCESS标志的含义CreateProcess:它的用途是用于控制台程序,而不是让它们使用父级继承的控制台。

实际上,要使进程与其父进程 A 分离,唯一的方法是启动进程 B,该进程将启动进程 C 并退出进程 B。然后进程 C 不再是 A 的后代,如果你杀死 A,C会活着。

为了有趣的概念,这里有一个 NSIS 脚本,如果由 Chrome 启动,它将自行重生。如果您在消息框显示时使用 ProcessExplorer 或 ProcessHacker 查看进程,您将看到可见设置不是 chrome 的子项...感谢 Anders 帮助我调试调用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
于 2012-12-18T16:49:26.487 回答