简体   繁体   中英

NSIS - See if a given process has shown a window

I run a certain process via ExecShell from my NSIS installer. That process takes sometime to start (5 - 40 seconds maybe), during which I want the NSIS window to remain visible.

The problem is that while the process itself starts almost instantly, it is sometime before a user would see anything, thus I want the NSIS installer window to remain visible UNTIL the started process's main window (or any window for that matter is shown).

What I need to know thus is how do I get processid from ExecShell (can't use Exec or ExecWait for other reasons), and then how do I use that process id to see if the window has been shown (I know I can do it via a simple sleep, check, goto loop, so basically I am trying to figure out the check part of it)?

So, how exactly can I know if the process I spawned using ShellExec has shown a GUI. This needs to work in Windows XP SP3 and up.

Thank you.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM