Seize the day

POST : SDP for win32/빌드,배포 자동화

[NSIS 설치 프로그램] 설치후 사용자 권한으로 작업 실행하기

  윈도우 XP에서는 일반 사용자 권한을 가진 계정(윈도우 사용자 계정)에서는  C:\program files 폴더에 새로운 파일 쓰기나 레지스트리 HKLM에 쓰기 권한이 없다. 따라서 새 프로그램 설치하는 것도 제한적이게 되었는데 비스타 이후에는 UAC(사용자 계정 콘트롤)이라는 기능이 도입되면서 일반 사용자 계정에서도 관리자 계정으로 로그인 한 후 프로그램을 설치하는 것이 가능해 졌다.  UAC는 관리자 계정으로 로그인하여 프로그램을 실행하더라도 기본적으로 일반 사용자 권한으로 프로그램이 실행되며, 관리자 권한이 필요한 기능은 권한 상승을 거쳐서 처리하도록 되어 있다.  이런 환경에서 설치 프로그램에 조금을 신경을 써야할 문제가 생긴다. 


  일반 사용자 계정에서 A에서 프로그램을 설치할 경우 관리자 계정 B로 로그인 후 설치 프로그램이 실행된다. 이 경우 설치 프로그램이 접근하는 HKCU 나 데스크탑 폴더 경로 등 사용자 프로필 경로 등은 관리자 계정 B의 경로를 리턴한다. 예를들어 IE의 툴바 플러그인에서 마우스 우클릭 메뉴 아이템 MenuExt는 HKCU 레지스트리에 기록을 하여야 하는데 설치 프로그램에서는 계정 B의 HKCU에 기록이 되기 때문에 설치후 실행되는 일반 계정 A에서는 반영이 되지 않는 문제가 발생한다.  따라서 설치는 관리자 계정으로 하되 설치가 끝난 후 로그인한 사용자 계정으로 추가 작업을 할 수 있는 방법이 필요하다. 


  두 번째 문제는 관리자 계정에서 프로그램을 설치하더라도 권한 문제가 발생할 수 있다. 설치 프로그램에서 설치 완료후 최초 실행되는 프로그램은 관리자 계정으로 실행이 되는데, 관리자 권한으로 데이타 파일을 새로 생성 한 경우, 프로그램을 종료후  그 프로그램을 다시 실행했을 때는 일반 권한으로 실행되기에 해당 데이타 파일에 대한 쓰기 권한 문제가 발생할 수 있다. 이 경우에는 항상 관리자 권한으로 실행시켜줘야 문제가 해결된다. 


  이 문제를 해결할 간단한 방법은 관리자 권한으로 프로그램을 설치하는 것이 아니라 사용자 권한이 필요한 곳에 파일을 복사하고 HKLM이 아니라 HKCU에만 기록하는 방법으로 설치 프로그램을 작성하는 것이다.  초기 구글 크롬에서 사용하는 방법이며 요즘 다수 프로그램이 이런 방식을 사용한다. XP에 설치되던 프로그램을 큰 변경없이 사용할수 있으며 웹마에서도 동일한 방법을 사용한다.

참조 : http://www.klopfenstein.net/lorenz.aspx/simple-nsis-installer-with-user-execution-level


  두 번째 방법은 설치 프로그램을 런처로 한 법 묶는 방법이다. 


SetupLauncher.exe  (일반 사용자 권한의 실행됨, Setup.exe의 실행이 끝난 후 설치 후 작업을 사용자 권한으로 실행)

                   |_______________> Setup.exe  (관리자 권한으로 실행됨, 파일복사 HKLM 쓰기 등)


결론 적으로 SetupLauncher라는 NSIS 프로그램을 하나 더 작성해야 하는데 동작 순서는 아래와 같다. 


1. SetupLauncher.exe는 항상 사용자 권한으로 실행된다.  NSIS 코드중에 아래처럼 user로 설청하여 파일명에 Setup이 들어가 있어도 사용자 권한으로 실행이 된다. 

     RequestExecutionLevel user


Function .onInit

    ; 런처로 들어온 모든 파라미터를 얻는다

    ${StdUtils.GetAllParameters} $ALL_PARAMS $1

FunctionEnd



2.  진짜 셋업 프로그램을 temp 폴더에 복사 한 후에 실행시키고 종료 되기를 기다린다. 

     ExecWait 를 이용하면 될 줄 알았는데 NSIS에서는 제대로 동작하지 않는다. 

     ExecShell "open" 으로 실행하면 가능한데 설치가 완료되기를 기다려 주지 않아서 사용할 수 없다. 

     셋업을 실행할 때는 런처 실행시 전달된 파라미터도 그대로 전달해주어야 한다. 


    이 문제를 해결하기 위해서 ExecShellWait 나 UAC plugin 같은게 있는데 다 사용하기 쉽지 않았고 구글링해보니 

    https://code.google.com/p/mulder/source/browse/trunk/Utils/nsis_stdutils/?r=367

    에서 배포하는 플러그인이 그나마 유용했다. 

StrCpy $INSTDIR "$TEMP\_LT2_\$R0$R1"


SetOutPath "$INSTDIR"

SetOverwrite on

File /oname=LT2Setup.exe "Setup.exe"


    ; 진짜설치 파일을 실행한다.

${StdUtils.ExecShellWait} $0 "$INSTDIR\LT2Setup.exe" "open" "$ALL_PARAMS" ;try to launch the process

    

    SetOutPath "$TEMP" ;for delete temp dir


${If} $0 == "error"

   MessageBox MB_OK|MB_TOPMOST "설치를 취소하였습니다. Install canceled!"

        Delete "$INSTDIR\LT2Setup.exe"

        RMdir $INSTDIR        

   Abort

${EndIf}


    ${If} $0 == "no_wait"

   MessageBox MB_OK|MB_TOPMOST "설치중 알 수없는 오류가 발생하였습니다. Unknown error!"

        Delete "$INSTDIR\LT2Setup.exe"

        RMdir $INSTDIR        

   Abort

${EndIf}


    ; 설치완료 기다리기

${StdUtils.WaitForProc} $0




     진짜 셋업 프로그램은 설치 성공 여부와 설치 완료 후 사용자 권한으로 실행할 프로그램의 경로 기록한다. 

    

Function .onInit

  DeleteRegValue HKLM "Software\Lee-tzsche2" "SetupResult" 

  DeleteRegValue HKLM "Software\Lee-tzsche2" "SetupRun" 

FunctionEnd


Function .onInstSuccess

    WriteRegStr HKLM "Software\Lee-tzsche2" "SetupResult" "1"

    WriteRegStr HKLM "Software\Lee-tzsche2" "SetupRun" "$INSTDIR\Lee-tzsche.exe"

FunctionEnd




3. 런처는 진짜 설치 프로그램의 실행이 종료되면 설치 성공 여부와 실행 경로를 얻어와 실행한다. 

    

     ; 설치가 성공하면 실행한다. (취소 체크)

    ReadRegStr $R0 HKLM "Software\Lee-tzsche2" "SetupResult"

${If} $R0 == "1"

ReadRegStr $R1 HKLM "Software\Lee-tzsche2" "SetupRun"

${If} $R1 != ""

Exec $R1

${EndIf}

${EndIf}

    

       # 임시폴더 삭제

Sleep 100

Delete "$INSTDIR\LT2Setup.exe"

RMdir $INSTDIR   



첨부 파일: 


플러그인 https://code.google.com/p/mulder/source/browse/trunk/Utils/nsis_stdutils/?r=367

StdUtils.2013-02-21.zip


런처

AppLauncher.nsi





top

posted at

2013. 10. 10. 23:40


CONTENTS

Seize the day
BLOG main image
김대정의 앱 개발 노트와 사는 이야기
RSS 2.0Tattertools
공지
아카이브
최근 글 최근 댓글
카테고리 태그 구름사이트 링크