2014-12-17 2 views
0

NSIS 설치 프로그램에서 ExecShell을 통해 특정 프로세스를 실행합니다. 이 프로세스는 언젠가 (5 ~ 40 초 정도) 시작할 것입니다. 그 동안 NSIS 창이 계속 보이기를 원합니다.NSIS - 주어진 프로세스가 창을 표시하는지 확인

문제는 프로세스 자체가 거의 즉시 시작되지만 언젠가는 사용자가 아무 것도 볼 수 없기 때문에 NSIS 설치 프로그램 창이 표시되기를 원합니다. 시작한 프로세스의 주 창 (또는 해당 창은 표시).

그래서 내가 알아야 할 것은 Execidhell ​​(다른 이유로 Exec 또는 ExecWait을 사용할 수 없음)에서 processid를 얻은 다음 해당 프로세스 ID를 사용하여 창이 표시되었는지 확인하는 것입니다. 간단한 수면, 체크, 고토 루프를 통해 할 수 있다는 것을 알고 있습니다. 그래서 기본적으로 체크 부분을 알아 내려고 노력하고 있습니까?)

그래서 ShellExec을 사용하여 생성 한 프로세스에 GUI가 표시되는지 정확히 알 수 있습니까? 이것은 Windows XP SP3 이상에서 작동해야합니다.

감사합니다.

+0

왜 Exec이 아닌 일반 Exec가 필요합니까? .exe 또는 비 실행 파일 형식을 시작하고 있습니까? – Anders

+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 
+0

UAC를 사용하여 하위 프로세스를 향상시키는 경우 이것이 작동하는지 잘 모르겠습니다. UAC로 승격 된 하위 프로세스에 대한 액세스 권한이있는 MSDN 문서는 믿을 수 없습니다. – Anders

+0

빠른 답변 감사드립니다. 그것은 일종의 일을하는 것처럼 보이지만, 설치자가 화면을 숨기고 있기 때문에 (화면을 찾았 기 때문에) 설치 프로그램과 화면에 나타나는 응용 프로그램의 실제 창 사이에 5 ~ 10 초 정도의 지연이있는 것을 제외하면 문제가되는 것 같습니다. 왜 그런가? 필터를 추가 할 수 있습니다 (예 : window.classname.startswith ("WinForms ..."))? –

+0

또한, ExecWait과 비슷한 것을 사용하고 있지만 Shell을 사용하고있는 것으로 나타났습니다. 앱을 시작하고 창 작업을 수행 한 다음 앱을 종료 할 때 (예 : WaitForSingleObject가없는 경우) 다른 설치 프로그램 로직을 계속 진행하면 어떨까요? –