我从NSIS安装程序通过ExecShell运行某个进程。该过程需要一些时间才能开始(可能是5 - 40秒),在此期间我希望NSIS窗口保持可见。
问题在于,虽然进程本身几乎立即启动,但是在用户看到任何内容之前的某个时间,因此我希望NSIS安装程序窗口保持可见,直到启动进程的主窗口(或任何窗口为那件事就显示了。)
我需要知道的是如何从ExecShell获取processid(由于其他原因不能使用Exec或ExecWait),然后如何使用该进程id来查看窗口是否已显示(我知道我可以通过一个简单的睡眠,检查,转到循环来做到这一点,所以基本上我试图找出它的检查部分)?
那么,我怎么知道我使用ShellExec生成的进程是否显示了GUI。这需要在Windows XP SP3及更高版本中运行。
谢谢。
答案 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