aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--installer/UAC.nsh191
-rw-r--r--installer/UltraStar Deluxe.nsi102
-rw-r--r--installer/dependencies/plugins/UAC.dllbin0 -> 17408 bytes
-rw-r--r--installer/settings/files_main_install.nsh14
4 files changed, 274 insertions, 33 deletions
diff --git a/installer/UAC.nsh b/installer/UAC.nsh
new file mode 100644
index 00000000..b21e72ff
--- /dev/null
+++ b/installer/UAC.nsh
@@ -0,0 +1,191 @@
+/*
+=======================
+UAC helper include file
+.......................
+
+Macros starting with UAC.I should only be called from the installer and vice versa for UAC.U macros.
+
+*/
+!ifndef UAC_HDR__INC
+!define UAC_HDR__INC
+!include LogicLib.nsh
+
+!define UAC.RunElevatedAndProcessMessages 'UAC::RunElevated '
+!define UAC.Unload 'UAC::Unload '
+!define UAC.StackPush 'UAC::StackPush '
+
+/*!macro _UAC.BuildOnInitElevationFunc _funcprefix
+Function ${_funcprefix}onInit
+!ifmacrodef
+FunctionEnd
+!macroend*/
+
+!macro _UAC.GenerateSimpleFunction _funcprefix _funcName _funcCode
+Function ${_funcprefix}${_funcName}
+${_funcCode}
+#messagebox mb_ok "${_funcprefix}${_funcName}"
+FunctionEnd
+!macroend
+
+!macro _UAC.TryDef _d _v
+!ifndef ${_d}
+!define ${_d} "${_v}"
+!endif
+!macroend
+
+!macro _UAC.InitStrings _modeprefix
+!insertmacro _UAC.TryDef UACSTR.UnDataFile "UAC.dat"
+!insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvWinErr "Unable to elevate , error $0"
+!ifNdef __UNINSTALL__
+ !insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvAbortReqAdmin "This installer requires admin access, aborting!"
+ !insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvMustTryAgain "This installer requires admin access, try again"
+ !else
+ !insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvAbortReqAdmin "This uninstaller requires admin access, aborting!"
+ !insertmacro _UAC.TryDef UACSTR.${_modeprefix}ElvMustTryAgain "This uninstaller requires admin access, try again"
+ !endif
+!macroend
+
+!ifmacroNdef _UAC.GenerateUninstallerTango
+!macro _UAC.GenerateUninstallerTango UninstallerFileName
+!ifdef __GLOBAL__
+ !error "UAC: Needs to be called inside a function"
+ !endif
+!ifNdef __UNINSTALL__
+ !error "UAC: _UAC.GenerateUninstallerTango should only be called by uninstaller, see http://forums.winamp.com/showthread.php?threadid=280330"
+ !endif
+!ifNdef UAC_UNINSTALLERTANGOFORALLPLATFORMS
+ !include WinVer.nsh
+ !endif
+!insertmacro _UAC.InitStrings 'U.'
+ReadIniStr $0 "$ExeDir\${UACSTR.UnDataFile}" UAC "Un.Ready"
+${IF} $0 != 1
+!ifNdef UAC_UNINSTALLERTANGOFORALLPLATFORMS
+${AndIf} ${AtLeastWinVista}
+!endif
+ InitPluginsDir
+ WriteIniStr "$PluginsDir\${UACSTR.UnDataFile}" UAC "Un.Ready" 1
+ CopyFiles /SILENT "$EXEPATH" "$PluginsDir\${UninstallerFileName}"
+ StrCpy $0 ""
+ ${IfThen} ${Silent} ${|} StrCpy $0 "/S " ${|}
+ ExecWait '"$PluginsDir\${UninstallerFileName}" $0/NCRC _?=$INSTDIR' $0
+ SetErrorLevel $0
+ Quit
+ ${EndIf}
+!macroend
+!endif
+
+!ifmacroNdef _UAC.GenerateOnInitElevationCode
+!macro _UAC.GenerateOnInitElevationCode _modeprefix
+!ifndef __FUNCTION__
+ !error "UAC: Needs to be called inside a function"
+ !endif
+!insertmacro _UAC.InitStrings ${_modeprefix}
+!define _UAC.GOIECUniq L${__LINE__}
+UAC_Elevate_${_UAC.GOIECUniq}:
+UAC::RunElevated
+StrCmp 1223 $0 UAC_ElevationAborted_${_UAC.GOIECUniq} ; UAC dialog aborted by user?
+StrCmp 0 $0 0 UAC_Err_${_UAC.GOIECUniq} ; Error?
+StrCmp 1 $1 0 UAC_Success_${_UAC.GOIECUniq} ;Are we the real deal or just the wrapper?
+Quit
+UAC_Err_${_UAC.GOIECUniq}:
+MessageBox mb_iconstop "${UACSTR.${_modeprefix}ElvWinErr}"
+Abort
+UAC_ElevationAborted_${_UAC.GOIECUniq}:
+MessageBox mb_iconstop "${UACSTR.${_modeprefix}ElvAbortReqAdmin}"
+Abort
+UAC_Success_${_UAC.GOIECUniq}:
+# if $0==0 && $3==1, we are a member of the admin group (Any OS)
+# if $0==0 && $1==0, UAC not supported (Probably <NT6), run as normal?
+# if $0==0 && $1==3, we can try to elevate again
+StrCmp 1 $3 /*+4*/ UAC_Done_${_UAC.GOIECUniq} ;Admin?
+StrCmp 3 $1 0 UAC_ElevationAborted_${_UAC.GOIECUniq} ;Try again or abort?
+MessageBox mb_iconexclamation "${UACSTR.${_modeprefix}ElvMustTryAgain}" ;Inform user...
+goto UAC_Elevate_${_UAC.GOIECUniq} ;...lets try again
+UAC_Done_${_UAC.GOIECUniq}:
+!undef _UAC.GOIECUniq
+!macroend
+!endif
+
+!define UAC.I.Elevate.AdminOnly '!insertmacro UAC.I.Elevate.AdminOnly '
+!macro UAC.I.Elevate.AdminOnly
+!insertmacro _UAC.GenerateOnInitElevationCode 'I.'
+!macroend
+
+!define UAC.U.Elevate.AdminOnly '!insertmacro UAC.U.Elevate.AdminOnly '
+!macro UAC.U.Elevate.AdminOnly _UninstallerName
+!ifNdef UAC_DISABLEUNINSTALLERTANGO
+ !insertmacro _UAC.GenerateUninstallerTango "${_UninstallerName}"
+ !endif
+!insertmacro _UAC.GenerateOnInitElevationCode 'U.'
+!macroend
+
+!define UAC.AutoCodeUnload '!insertmacro UAC.AutoCodeUnload '
+!macro UAC.AutoCodeUnload _HasUninstaller
+!insertmacro _UAC.GenerateSimpleFunction "" .OnInstFailed '${UAC.Unload}'
+!insertmacro _UAC.GenerateSimpleFunction "" .OnInstSuccess '${UAC.Unload}'
+!ifNdef MUI_INCLUDED
+ !insertmacro _UAC.GenerateSimpleFunction "" .onUserAbort '${UAC.Unload}'
+ !else
+ !ifNdef MUI_CUSTOMFUNCTION_ABORT
+ !error "UAC: must call $$ {UAC.Unload} in MUI_CUSTOMFUNCTION_ABORT!"
+ !endif
+ !endif
+!if "${_HasUninstaller}" != ""
+ !insertmacro _UAC.GenerateSimpleFunction "un" .onUninstFailed '${UAC.Unload}'
+ !insertmacro _UAC.GenerateSimpleFunction "un" .onUninstSuccess '${UAC.Unload}'
+ !ifNdef MUI_INCLUDED
+ !insertmacro _UAC.GenerateSimpleFunction "un" .onUserAbort '${UAC.Unload}'
+ !else
+ !ifNdef MUI_CUSTOMFUNCTION_ABORT
+ !error "UAC: must call $$ {UAC.Unload} in MUI_CUSTOMFUNCTION_(UN)ABORT!"
+ !endif
+ !endif
+ !endif
+!macroend
+
+!define UAC.FastCallFunctionAsUser '!insertmacro UAC.FastCallFunctionAsUser '
+!macro UAC.FastCallFunctionAsUser _func _var
+GetFunctionAddress ${_var} ${_func}
+UAC::ExecCodeSegment ${_var}
+!macroend
+!define UAC.CallFunctionAsUser '!insertmacro UAC.CallFunctionAsUser '
+!macro UAC.CallFunctionAsUser _func
+push $R9
+!insertmacro UAC.FastCallFunctionAsUser ${_func} $R9
+pop $R9
+!macroend
+
+!define UAC.FastCallGetOuterInstanceHwndParent UAC::GetOuterHwnd
+!define UAC.GetOuterInstanceHwndParent '!insertmacro UAC.GetOuterInstanceHwndParent '
+!macro UAC.GetOuterInstanceHwndParent _var
+push $0
+${UAC.FastCallGetOuterInstanceHwndParent}
+Exch $0
+Pop ${_var}
+!macroend
+
+
+
+!macro _UAC.DumpEx _disp _f _fp _v
+${_f} ${_fp}
+DetailPrint "${_disp}=${_v}"
+!macroend
+!macro _UAC.Dump _f _fp _v
+!insertmacro _UAC.DumpEx `${_f}` `${_f}` `${_fp}` `${_v}`
+!macroend
+!macro _UAC.DbgDetailPrint
+push $0
+push $1
+System::Call /NoUnload "advapi32::GetUserName(t.r0,*i${NSIS_MAX_STRLEN})"
+System::Call "Kernel32::GetComputerName(t.r1,*i${NSIS_MAX_STRLEN})"
+DetailPrint "$1\$0"
+;!insertmacro _UAC.DumpEx "User" System::Call "advapi32::GetUserName(t.r0,*i${NSIS_MAX_STRLEN})" $0
+!insertmacro _UAC.DumpEx "CmdLine" "" "" "$CmdLine"
+!insertmacro _UAC.Dump UAC::IsAdmin "" $0
+!insertmacro _UAC.Dump UAC::SupportsUAC "" $0
+!insertmacro _UAC.Dump UAC::GetElevationType "" $0
+pop $1
+pop $0
+!macroend
+
+!endif /* ifndef UAC_HDR__INC */ \ No newline at end of file
diff --git a/installer/UltraStar Deluxe.nsi b/installer/UltraStar Deluxe.nsi
index 497f53ee..125dfefc 100644
--- a/installer/UltraStar Deluxe.nsi
+++ b/installer/UltraStar Deluxe.nsi
@@ -7,6 +7,7 @@
!include LogicLib.nsh
!include InstallOptions.nsh
!include nsDialogs.nsh
+!include UAC.nsh
; ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~
; Variables
@@ -49,8 +50,8 @@ InstallDir "$PROGRAMFILES\${name}"
InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\UltraStar Deluxe" "InstallDir"
; Windows Vista / Windows 7:
-
-RequestExecutionLevel admin
+; must be "user" for UAC plugin
+RequestExecutionLevel user
; ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~ ~+~
; Interface Settings
@@ -109,8 +110,16 @@ RequestExecutionLevel admin
!define MUI_FINISHPAGE_TEXT_LARGE
!define MUI_FINISHPAGE_TEXT "$(page_finish_txt)"
-!define MUI_FINISHPAGE_RUN "$INSTDIR\${exe}.exe"
+; MUI_FINISHPAGE_RUN is executed as admin by default.
+; To get the config.ini location right it must be executed with user
+; rights instead.
+!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_NOTCHECKED
+!define MUI_FINISHPAGE_RUN_FUNCTION RunAppAsUser
+
+Function RunAppAsUser
+ UAC::ShellExec 'open' '' '$INSTDIR\${exe}.exe' '' '$INSTDIR'
+FunctionEnd
!define MUI_FINISHPAGE_LINK "$(page_finish_linktxt)"
!define MUI_FINISHPAGE_LINK_LOCATION "${homepage}"
@@ -135,7 +144,7 @@ RequestExecutionLevel admin
; Start menu page
-var ICONS_GROUP
+Var ICONS_GROUP
!define MUI_STARTMENUPAGE_NODISABLE
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${name}"
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
@@ -149,6 +158,50 @@ var ICONS_GROUP
Page custom Settings
+
+; User data info
+
+Var UseAppData ; true if APPDATA is used for user data, false for INSTDIR
+Var UserDataPath ; Path to user data dir (e.g. $INSTDIR)
+Var ConfigIniPath ; Path to config.ini (e.g. "$INSTDIR\config.ini")
+
+; Checks for write permissions on $INSTDIR\config.ini.
+; This function creates $INSTDIR\config.use as a marker file if
+; the user has write permissions.
+; Note: Must be run with user privileges
+Function CheckInstDirUserPermissions
+ ClearErrors
+ ; try to open the ini file.
+ ; Use "append" mode so an existing config.ini is not destroyed.
+ FileOpen $0 "$INSTDIR\config.ini" a
+ IfErrors end
+ ; we have write permissions -> create a marker file
+ FileOpen $1 "$INSTDIR\config.use" a
+ FileClose $1
+end:
+ FileClose $0
+FunctionEnd
+
+; Determines the directory used for config.ini and other user
+; settings and data.
+; Sets $UseAppData, $UserDataPath and $ConfigIniPath
+Function DetermineUserDataDir
+ Delete "$INSTDIR\config.use"
+ !insertmacro UAC.CallFunctionAsUser CheckInstDirUserPermissions
+ IfFileExists "$INSTDIR\config.use" 0 notexists
+ StrCpy $UseAppData false
+ StrCpy $UserDataPath "$INSTDIR"
+ Goto end
+notexists:
+ StrCpy $UseAppData true
+ SetShellVarContext current
+ StrCpy $UserDataPath "$APPDATA\ultrastardx"
+ SetShellVarContext all
+end:
+ Delete "$INSTDIR\config.use"
+ StrCpy $ConfigIniPath "$UserDataPath\config.ini"
+FunctionEnd
+
Function Settings
!insertmacro INSTALLOPTIONS_WRITE "Settings-$LANGUAGE" "Field 18" "State" "$INSTDIR\songs"
@@ -187,32 +240,17 @@ Function Settings
!insertmacro INSTALLOPTIONS_READ $sorting "Settings-$LANGUAGE" "Field 15" "State"
!insertmacro INSTALLOPTIONS_READ $songdir "Settings-$LANGUAGE" "Field 18" "State"
- ; Write all variables to config.ini
-
- var /GLOBAL path_config
- var /GLOBAL path_configini
-
- ${If} ${AtLeastWinVista}
- SetShellVarContext current
- StrCpy $path_config "$APPDATA\ultrastardx"
- SetShellVarContext all
- ${Else}
- StrCpy $path_config "$INSTDIR"
- ${EndIf}
-
- StrCpy $path_configini "$path_config\config.ini"
-
- WriteINIStr "$path_configini" "Game" "Language" "$language2"
- WriteINIStr "$path_configini" "Game" "Tabs" "$tabs"
- WriteINIStr "$path_configini" "Game" "Sorting" "$sorting"
+ WriteINIStr "$ConfigIniPath" "Game" "Language" "$language2"
+ WriteINIStr "$ConfigIniPath" "Game" "Tabs" "$tabs"
+ WriteINIStr "$ConfigIniPath" "Game" "Sorting" "$sorting"
- WriteINIStr "$path_configini" "Graphics" "FullScreen" "$fullscreen"
- WriteINIStr "$path_configini" "Graphics" "Resolution" "$resolution"
+ WriteINIStr "$ConfigIniPath" "Graphics" "FullScreen" "$fullscreen"
+ WriteINIStr "$ConfigIniPath" "Graphics" "Resolution" "$resolution"
${If} $songdir != "$INSTDIR\songs"
- WriteINIStr "$path_configini" "Directories" "SongDir1" "$songdir"
+ WriteINIStr "$ConfigIniPath" "Directories" "SongDir1" "$songdir"
${EndIf}
-
+
FunctionEnd ; Settings page End
!insertmacro MUI_PAGE_FINISH
@@ -333,6 +371,8 @@ Section $(name_section1) Section1
SetOutPath $INSTDIR
SetOverwrite try
+ Call DetermineUserDataDir
+
!include "${path_settings}\files_main_install.nsh"
; Create Shortcuts:
@@ -487,6 +527,8 @@ FunctionEnd
Function .onInit
+ ${UAC.I.Elevate.AdminOnly}
+
var /GLOBAL version
StrCpy $version "1.1beta"
@@ -560,3 +602,11 @@ continue:
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
+
+Function .onInstFailed
+ ${UAC.Unload}
+FunctionEnd
+
+Function .onInstSuccess
+ ${UAC.Unload}
+FunctionEnd \ No newline at end of file
diff --git a/installer/dependencies/plugins/UAC.dll b/installer/dependencies/plugins/UAC.dll
new file mode 100644
index 00000000..edf21305
--- /dev/null
+++ b/installer/dependencies/plugins/UAC.dll
Binary files differ
diff --git a/installer/settings/files_main_install.nsh b/installer/settings/files_main_install.nsh
index a79d4991..10afc6f6 100644
--- a/installer/settings/files_main_install.nsh
+++ b/installer/settings/files_main_install.nsh
@@ -33,19 +33,19 @@ CreateDirectory $INSTDIR\plugins
CreateDirectory $INSTDIR\covers
CreateDirectory $INSTDIR\songs
-${If} ${AtLeastWinVista}
+${If} $UseAppData == true
; Create folders in appdata for current user
SetShellVarContext current
- CreateDirectory $APPDATA\ultrastardx
- CreateDirectory $APPDATA\ultrastardx\screenshots
- CreateDirectory $APPDATA\ultrastardx\playlists
+ CreateDirectory $UserDataPath
+ CreateDirectory $UserDataPath\screenshots
+ CreateDirectory $UserDataPath\playlists
SetOutPath "$INSTDIR"
- CreateShortCut "screenshots.lnk" "$APPDATA\ultrastardx\screenshots"
- CreateShortCut "playlists.lnk" "$APPDATA\ultrastardx\playlists"
- CreateShortCut "config.ini.lnk" "$APPDATA\ultrastardx\config.ini"
+ CreateShortCut "screenshots.lnk" "$UserDataPath\screenshots"
+ CreateShortCut "playlists.lnk" "$UserDataPath\playlists"
+ CreateShortCut "config.ini.lnk" "$ConfigIniPath"
SetShellVarContext all
${EndIf}