1
votes

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
2
The .onInit code you pasted here does not match the code you linked to! The code you linked to has a clear problem, cannot really tell if the code pasted here has a problem without testing myself but I'm not going to do that until you clarify which code I'm supposed to test. Having some information about the NSIS/UAC plug-in/Windows versions used would also be nice... - Anders
@Anders I am pushing and trying several things while I type this. Sorry if it differs by now. Consider the code in the link the current code I am running. Also, I am building it on a Windows 2008 64 bit server and testing the installation procedure on a windows 10 machine, also 64 bit. - Gooey
@Anders I have undone some of my experimental changes and pushed them. I will refrain pushing to it for now as it indeed it is confusing when people are looking at it. - Gooey

2 Answers

2
votes

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...

1
votes

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}