NSIS - 查看给定进程是否显示了一个窗口

时间:2014-12-17 16:45:52

标签: windows user-interface process nsis

我从NSIS安装程序通过ExecShell运行某个进程。该过程需要一些时间才能开始(可能是5 - 40秒),在此期间我希望NSIS窗口保持可见。

问题在于,虽然进程本身几乎立即启动,但是在用户看到任何内容之前的某个时间,因此我希望NSIS安装程序窗口保持可见,直到启动进程的主窗口(或任何窗口为那件事就显示了。)

我需要知道的是如何从ExecShell获取processid(由于其他原因不能使用Exec或ExecWait),然后如何使用该进程id来查看窗口是否已显示(我知道我可以通过一个简单的睡眠,检查,转到循环来做到这一点,所以基本上我试图找出它的检查部分)?

那么,我怎么知道我使用ShellExec生成的进程是否显示了GUI。这需要在Windows XP SP3及更高版本中运行。

谢谢。

1 个答案:

答案 0 :(得分:2)

RequestExecutionLevel user
Page InstFiles

!include LogicLib.nsh
!include WinMessages.nsh ; For SW_*

Var IsSlowFakeApp ; We can also pretend to be a silly little app that is slow to start up, this is just so the example code has no external dependencies

Function .onInit
StrCpy $0 $CMDLINE 1 -1
${If} $0 == "?"
    StrCpy $IsSlowFakeApp 1
    Sleep 3333
${EndIf}
FunctionEnd


Function StartMyAppAndWaitForWindow
StrCpy $0 "$ExePath" ; Application
StrCpy $1 "?" ; Parameters
!define SEE_MASK_NOCLOSEPROCESS 0x40
DetailPrint 'Starting "$0" $1'
System::Store S
System::Call '*(i60,i${SEE_MASK_NOCLOSEPROCESS},i$hwndparent,i0,tr0,tr1,i0,i${SW_SHOW},i,i,i,i,i,i,i)i.r0'
System::Call 'SHELL32::ShellExecuteEx(ir0)i.r1'
${If} $1 <> 0
    System::Call '*$0(i,i,i,i,i,i,i,i,i,i,i,i,i,i,i.r1)'
    System::Call 'USER32::WaitForInputIdle(ir1,2000)i'

    System::Call 'KERNEL32::GetProcessId(ir1)i.r2' ; MSDN says this function is XP.SP1+
    StrCpy $3 $2 ; Not found a window yet, keep looping

    ; Call EnumWindows until we find a window matching our target process id in $2
    System::Get '(i.r5, i) iss'
    Pop $R0
    callEnumWindows:
        System::Call 'USER32::EnumWindows(k R0, i) i.s'
        loopEnumWindows:
            Pop $4
            StrCmp $4 "callback1" 0 doneEnumWindows
            System::Call 'USER32::GetWindowThreadProcessId(ir5,*i0r4)'
            ${If} $4 = $2
                System::Call 'USER32::IsWindowVisible(ir5)i.r4'
                ${IfThen} $4 <> 0 ${|} StrCpy $3 0 ${|} ; Found a visible Window
            ${EndIf}
            Push $3 ; EnumWindows callback's return value
            System::Call "$R0"
            Goto loopEnumWindows
        doneEnumWindows:
    ${If} $3 <> 0
        Sleep 1000
        Goto callEnumWindows
    ${EndIf}
    System::Free $R0

    ; Hide installer while app runs
    /*HideWindow
    System::Call 'KERNEL32::WaitForSingleObject(ir1,i-1)'
    BringToFront*/
    System::Call 'KERNEL32::CloseHandle(ir1)'
${EndIf}
System::Free $0
System::Store L
FunctionEnd

Section
${If} $IsSlowFakeApp <> 0
    SetCtlColors $HWNDPARENT 0xffffff 0xdd0000
    FindWindow $0 "#32770" "" $HWNDPARENT
    SetCtlColors $0 0xffffff 0xdd0000
    DetailPrint "This is a fake slow app and it will close soon..."
    Sleep 5555
    Quit
${Else}
    Call StartMyAppAndWaitForWindow
${EndIf}
SectionEnd