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