简体   繁体   中英

NSIS installer .onInit and un.onInit run twice because of UAC

Hello I am refactoring an old install script and run into the issue that the UAC plugin creates. Because of the !insertmacro Init "installer" the .onInit runs twice. The same goes for !insertmacro Init "uninstaller" and the un.onInit function.

Because of this, the installer and the uninstaller run twice which is not the behavior I want. I have read that the UAC creates an inner process with elevated permissions , which IS required as it touches the C:/ drive for example, but the outer process also runs the installer.

Because the install script is quite long I only paste the .onInit function. The whole .nsi script can be found here .

Commenting out the line with the !insertmacro makes sure the .onInit function runs once, but does not run the installer anymore. So how can I make the installer and the uninstaller only run once, with the right (admin) permissions?

I appreciate any suggestion or answer :)

Function .onInit
MessageBox MB_OK "In .onInit"
  SetShellVarContext all

  !insertmacro Init "installer"

  System::Call 'kernel32::CreateMutexA(i 0, i 0, t "Tribler") i .r1 ?e'

  Pop $R0
  StrCmp $R0 0 checkinst

  MessageBox MB_OK "The installer is already running."
  Abort

  checkinst:
  ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT}" "UninstallString"
  StrCmp $R0 "" done
  IfFileExists $R0 showuninstdialog done

  showuninstdialog:
  MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "${PRODUCT} is already installed. $\n$\nClick `OK` to remove the previous version or `Cancel` to cancel this upgrade." /SD IDCANCEL IDOK uninst
  Abort

  uninst:
    ClearErrors
    ; Laurens (2016-03-29): Retrieve the uninstallString stored in the register. Do NOT use $INSTDIR as this points to the current $INSTDIR var of the INSTALLER, 
    ; which is the default location at this point.
    ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT}" "UninstallString"
 MessageBox MB_OK "$R0"
    ExecWait '"$R0"' ;Do not copy the uninstaller to a temp file
    ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT}" "UninstallString"
    StrCmp $R0 "" done
    Abort
  done:

FunctionEnd

The code you linked to (at least when I looked at it) called both !insertmacro UAC_RunElevated and !insertmacro Init "installer" in .onInit so no wonder it ran multiple times. After calling !insertmacro UAC_RunElevated you must always check $0 because you might have to call Quit depending on its value!

I assume that Init macro is something I wrote(?) so it should work correctly ;)

I would personally recommend that you sacrifice the run checkbox on the finish page and then you probably don't have to use the UAC plug-in at all...

As far as I remember, the UAC plugin restarts the installer with a special parameter. You can check for that in your .onInit using GetParameters and GetOptions , then show a message conditionally:

# get all commandline parameters
${GetParameters} $0

# parse specific option
${GetOptions} $0 "/UAC:" $1

# do stuff
IfErrors 0 +2
MessageBox MB_OK "No admint" IDOK +2
MessageBox MB_OK "Admin"

Personally, I'd use LogicLib for the last part:

# do stuff
${If} $1 == ""
  MessageBox MB_OK "Not admin"
${Else}
 MessageBox MB_OK "Admin"
${Endif}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM