PageRenderTime 83ms CodeModel.GetById 40ms app.highlight 3ms RepoModel.GetById 37ms app.codeStats 0ms

/admin/win/nsi/nsis_uac/UAC_RealWorldFullyLoadedDualModeExample.nsi

http://github.com/tomahawk-player/tomahawk
Unknown | 242 lines | 219 code | 23 blank | 0 comment | 0 complexity | de4dcbb6f520d5d461ba5c24f8e1e3bc MD5 | raw file
  1/*
  2This sample supports two modes, installing as a normal user (single user install) AND as admin (all users install)
  3This sample uses the registry plugin, so you need to download that if you don't already have it
  4*/
  5
  6!define APPNAME "UAC_RealWorldFullyLoadedDualMode"
  7!define ELEVATIONTITLE "${APPNAME}: Elevate" ;displayed during elevation on our custom page
  8!define SMSUBDIR $StartMenuFolder ;"${APPNAME}"
  9!define UNINSTALLER_NAME "Uninstall ${APPNAME}.exe"
 10!define UNINSTALLER_REGSECTION "${APPNAME}"
 11!define RegPath.MSUninstall "Software\Microsoft\Windows\CurrentVersion\Uninstall"
 12Name "${APPNAME}"
 13OutFile "${APPNAME}.exe"
 14ShowInstDetails show
 15SetCompressor LZMA
 16RequestExecutionLevel user /* RequestExecutionLevel REQUIRED! */
 17!include MUI.nsh
 18!include UAC.nsh
 19!include LogicLib.nsh
 20!include Registry.nsh
 21!include nsDialogs.nsh	;for our custom page
 22!include FileFunc.nsh	;we need to parse the command line
 23
 24!insertmacro GetParameters
 25!insertmacro GetOptions
 26
 27!define MUI_CUSTOMFUNCTION_ABORT onAbort
 28!define MUI_CUSTOMFUNCTION_GUIINIT onGuiInit
 29!define MUI_COMPONENTSPAGE_NODESC
 30!define MUI_FINISHPAGE_NOAUTOCLOSE
 31!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\llama-blue.ico"
 32!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\llama-blue.ico"
 33!define MUI_WELCOMEPAGE_TITLE_3LINES
 34
 35var InstMode 	# 0: Single user, 1:All users, >1:elevated instance, perform page jump
 36var hKey 		# Reg hive
 37var hSelModeAdminRadio
 38var StartMenuFolder
 39
 40!macro SetMode IsAdmin
 41!if "${IsAdmin}" > 0
 42	SetShellVarContext all
 43	StrCpy $InstMode 1
 44	StrCpy $hKey HKLM
 45	!else
 46	SetShellVarContext current
 47	StrCpy $InstMode 0
 48	StrCpy $hKey HKCU
 49	!endif
 50!macroend
 51
 52Function .OnInit
 53!insertmacro SetMode 0
 54${GetParameters} $R9
 55${GetOptions} "$R9" UAC $0 ;look for special /UAC:???? parameter (sort of undocumented)
 56${Unless} ${Errors}
 57	UAC::IsAdmin
 58	${If} $0 < 1 
 59		SetErrorLevel 666 ;special return value for outer instance so it knows we did not have admin rights
 60		Quit 
 61		${EndIf}
 62	!insertmacro SetMode 1
 63	StrCpy $InstMode 2
 64	${EndIf}
 65FunctionEnd
 66
 67Function onGuiInit
 68${If} $InstMode >= 2
 69	${UAC.GetOuterInstanceHwndParent} $0
 70	${If} $0 <> 0 
 71		System::Call /NOUNLOAD "*(i,i,i,i)i.r1"
 72		System::Call /NOUNLOAD 'user32::GetWindowRect(i $0,i r1)i.r2'
 73		${If} $2 <> 0
 74			System::Call /NOUNLOAD "*$1(i.r2,i.r3)"
 75			System::Call /NOUNLOAD 'user32::SetWindowPos(i $hwndParent,i0,ir2,ir3,i0,i0,i 4|1)'
 76			${EndIf}
 77		ShowWindow $hwndParent ${SW_SHOW}
 78		ShowWindow $0 ${SW_HIDE} ;hide outer instance installer window
 79		System::Free $1
 80		${EndIf}
 81	${EndIf}
 82FunctionEnd
 83
 84Function Un.OnInit
 85!insertmacro SetMode 0
 86ReadRegDWORD $0 HKLM "${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" InstMode ;We saved the "mode" in the installer
 87${If} $0 U> 0
 88	; If it was installed for all users, we have to be admin to uninstall it
 89	${UAC.U.Elevate.AdminOnly} "${UNINSTALLER_NAME}"
 90	!insertmacro SetMode 1
 91	${EndIf}
 92FunctionEnd
 93
 94Function onAbort
 95${UAC.Unload}
 96FunctionEnd
 97
 98${UAC.AutoCodeUnload} 1 ;Auto-generate .OnInstFailed and .OnInstSuccess functions
 99
100!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipPageInElvModePreCB
101!insertmacro MUI_PAGE_WELCOME
102Page Custom ModeSelectionPageCreate ModeSelectionPageLeave
103!define MUI_PAGE_CUSTOMFUNCTION_PRE CmpntsPreCB
104!insertmacro MUI_PAGE_COMPONENTS
105!define MUI_PAGE_CUSTOMFUNCTION_PRE DirPreCB
106!insertmacro MUI_PAGE_DIRECTORY
107!insertmacro MUI_PAGE_STARTMENU 1 $StartMenuFolder
108!insertmacro MUI_PAGE_INSTFILES
109!define MUI_FINISHPAGE_TITLE_3LINES
110!define MUI_FINISHPAGE_RUN
111!define MUI_FINISHPAGE_RUN_FUNCTION FinishRunCB
112!insertmacro MUI_PAGE_FINISH
113!define MUI_WELCOMEPAGE_TITLE_3LINES
114!insertmacro MUI_UNPAGE_WELCOME
115!insertmacro MUI_UNPAGE_INSTFILES
116!insertmacro MUI_LANGUAGE "English"
117
118Function CmpntsPreCB
119GetDlgItem $0 $hwndparent 3
120${IfThen} $InstMode >= 1 ${|} EnableWindow $0 0 ${|} ;prevent user from going back and selecting single user so noobs don't end up installing as the wrong user
121FunctionEnd
122
123Function SkipPageInElvModePreCB
124${IfThen} $InstMode > 1 ${|} Abort ${|} ;skip this page so we get to the mode selection page
125FunctionEnd
126
127Function ModeSelectionPageCreate
128${If} $InstMode > 1 
129	StrCpy $InstMode 1
130	Abort ;skip this page and contine where the "parent" would have gone
131	${EndIf}
132!insertmacro MUI_HEADER_TEXT_PAGE "Select install type" "Blah blah blah blah"
133nsDialogs::Create /NOUNLOAD 1018
134Pop $0
135${NSD_CreateLabel} 0 20u 75% 20u "Blah blah blah blah select install type..."
136Pop $0
137System::Call "advapi32::GetUserName(t.r0, *i ${NSIS_MAX_STRLEN}r1) i.r2"
138${NSD_CreateRadioButton} 0 40u 75% 15u "Single User ($0)"
139Pop $0
140${IfThen} $InstMode U< 1 ${|} SendMessage $0 ${BM_SETCHECK} 1 0 ${|}
141${NSD_CreateRadioButton} 0 60u 75% 15u "All users"
142Pop $hSelModeAdminRadio
143${IfThen} $InstMode U> 0 ${|} SendMessage $hSelModeAdminRadio ${BM_SETCHECK} 1 0 ${|}
144nsDialogs::Show
145FunctionEnd
146
147!macro EnableCtrl dlg id state
148push $language
149GetDlgItem $language ${dlg} ${id}
150EnableWindow $language ${state}
151pop $language
152!macroend
153
154Function ModeSelectionPageLeave
155SendMessage $hSelModeAdminRadio ${BM_GETCHECK} 0 0 $9
156UAC::IsAdmin
157${If} $9 U> 0
158	${If} $0 <> 0
159		!insertmacro SetMode 1
160	${Else}
161		System::Call /NoUnload 'user32::GetWindowText(i $HwndParent,t.R1,i ${NSIS_MAX_STRLEN})' ;get original window title
162		System::Call /NoUnload 'user32::SetWindowText(i $HwndParent,t "${ELEVATIONTITLE}")' ;set out special title
163		StrCpy $2 "" ;reset special return, only gets set when sub process is executed, not when user cancels
164		!insertmacro EnableCtrl $HWNDParent 1 0 ;Disable next button, just because it looks good ;)
165		${UAC.RunElevatedAndProcessMessages}
166		!insertmacro EnableCtrl $HWNDParent 1 1
167		System::Call 'user32::SetWindowText(i $HwndParent,t "$R1")' ;restore title
168		${If} $2 = 666 ;our special return, the new process was not admin after all 
169			MessageBox mb_iconExclamation "You need to login with an account that is a member of the admin group to continue..."
170			Abort 
171		${ElseIf} $0 = 1223 ;cancel
172			Abort
173		${Else}
174			${If} $0 <> 0
175				${If} $0 = 1062
176					MessageBox mb_iconstop "Unable to elevate, Secondary Logon service not running!"
177				${Else}
178					MessageBox mb_iconstop "Unable to elevate, error $0 ($1,$2,$3)"
179				${EndIf} 
180				Abort
181			${EndIf}
182		${EndIf} 
183		Quit ;We now have a new process, the install will continue there, we have nothing left to do here
184	${EndIf}
185${EndIf}
186FunctionEnd
187
188Function DirPreCB
189${If} $InstDir == ""
190	${If} $InstMode U> 0
191		StrCpy $InstDir "$ProgramFiles\${APPNAME}"
192		${Else}
193		StrCpy $InstDir "$APPDATA\${APPNAME}"
194		${EndIf}
195	${EndIf}
196FunctionEnd
197
198Function FinishRunCB
199UAC::Exec "" "Notepad.exe" "$Windir\Win.INI" "$InstDir"
200FunctionEnd
201
202Function CreateSMShortcuts
203StrCpy ${SMSUBDIR} $9 ;stupid sync
204CreateDirectory "$SMPrograms\${SMSUBDIR}"
205CreateShortcut "$SMPrograms\${SMSUBDIR}\${APPNAME}.lnk" "$Windir\Notepad.exe"
206CreateShortcut "$SMPrograms\${SMSUBDIR}\Uninstall ${APPNAME}.lnk" "$InstDir\${UNINSTALLER_NAME}"
207FunctionEnd
208Function CreateDeskShortcuts
209CreateShortcut "$Desktop\${APPNAME}.lnk" "$Windir\Notepad.exe"
210FunctionEnd
211
212Section "!Required files"
213SectionIn RO
214SetOutPath -
215!insertmacro _UAC.DbgDetailPrint ;some debug info, useful during testing
216;Install files here...
217WriteUninstaller "$InstDir\${UNINSTALLER_NAME}"
218${registry::Write} "$hKey\${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" DisplayName "${APPNAME}" REG_SZ $0
219${registry::Write} "$hKey\${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" UninstallString "$InstDir\${UNINSTALLER_NAME}" REG_SZ $0
220${registry::Write} "$hKey\${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" InstMode $InstMode REG_DWORD $0
221${registry::Unload}
222SectionEnd
223
224Section "Startmenu Shortcuts"
225StrCpy $9 ${SMSUBDIR} ;this is stupid as hell, we need correct ${SMSUBDIR} in the outer process, this is the only way (plugins cannot enum "custom" var's AFAIK)
226${UAC.CallFunctionAsUser} CreateSMShortcuts
227SectionEnd
228Section "Desktop Shortcut"
229${UAC.CallFunctionAsUser} CreateDeskShortcuts
230SectionEnd
231
232Section Uninstall
233Delete "$InstDir\${UNINSTALLER_NAME}"
234Delete "$SMPrograms\${SMSUBDIR}\${APPNAME}.lnk"
235Delete "$SMPrograms\${SMSUBDIR}\Uninstall ${APPNAME}.lnk"
236RMDir "$SMPrograms\${SMSUBDIR}"
237Delete "$Desktop\${APPNAME}.lnk"
238
239RMDir "$InstDir"
240${registry::DeleteKey} "$hKey\${RegPath.MSUninstall}\${UNINSTALLER_REGSECTION}" $0
241${registry::Unload}
242SectionEnd