How to access InstallDirRegKey in NSIS - installation

I can specify installation directory and registry value in NSIS like this:
InstallDir "$PROGRAMFILES\CTVI"
InstallDirRegKey HKLM "Software\CTVI" "Install_Dir"
Now I can access InstallDir by using the notation $INSTDIR throughout the script. How do I similarly access InstallDirRegKey? Is there a similar notation as there exists for InstallDir? I tried $INSTDIRREGKEY but that is not. Now what I do is that I type HKLM "Software\CTVI" "Install_Dir" everytime I require it. But that is not so DRY :)

When the InstallDirRegKey attribute is used, NSIS will look-up the specified registry entry at startup and if it finds a path there it will place that value in $Instdir before any of your code runs...

Related

How to set the ALL USER Directory as an output directory for a installer created with NSIS

I am trying to install a file to ALL USER DOCUMENTS Directory(windows 7) using NSIS.
In my code i am setting "SetShellVarContext all" but still the files are getting installed at current user directory
Please help
Here is my code
# define installer name
OutFile "installer.exe"
# set desktop as install directory
InstallDir $DOCUMENTS
# default section start
Section
# define output path
SetShellVarContext all
SetOutPath $INSTDIR
# specify file to go in output path
File test.txt
# define uninstaller name
WriteUninstaller $INSTDIR\uninstaller.exe
#-------
# default section end
SectionEnd
# create a section to define what the uninstaller does.
# the section will always be named "Uninstall"
Section "Uninstall"
# Always delete uninstaller first
Delete $INSTDIR\uninstaller.exe
# now delete installed file
Delete $INSTDIR\test.txt
SectionEnd
SetShellVarContext does not affect the InstallDir attribute, you must manually set $InstDir:
Function .onInit
SetShellVarContext all
StrCpy $InstDir $Documents
FunctionEnd

Obtain Current Users %APPDATA% Path and not Admins

I am looking to get the path to the current users %APPDATA% folder.
Note: I am aware of the variable $APPDATA BUT if you run your installer with RequestExecutionLevel admin then $APPDATA will point to the admins roaming folder and NOT the current user's app data folder.
I need to find out the current users %APPDATA% path so I can write files to their roaming directory. Does anyone know how I can find this out?
RequestExecutionLevel admin
Section "Main"
MessageBox MB_OK "AppData is: $APPDATA" # knowtice that its the path to the admins folder not the current user's
SectionEnd
The term "Current User" is ambiguous, do you mean:
The user you get from WTSQueryUserToken()? (WinLogon)
The user that the shell's taskbar is running as? (GetShellWindow())
The user (parent process) that started your setup process?
All of those can be different users if you are having fun with runas!
The comment from Harry Johnston is spot on and once you start mixing %ProgramFiles% and %AppData% and/or HKLM and HKCU your setup is broken in multi-user scenarios. What happens when a different user starts the application? They are not going to have your files in their %AppData%.
If the addin is installed/registered in a global location you can install the AppData "template" files in %ProgramFiles%, %CommonProgramFiles% or %ALLUSERSPROFILE% and when your addin runs as a specific user for the first time you copy the files to %AppData%.
Active Setup could be used as a alternative but it will probably require a log-off/log-on cycle.
If you cannot implement the delayed copy/install for some reason you are left with hacks like the UAC plugin which gives you some access to the user that started your installer...
Ok, thanks for the advice but I found a nice plugin that tells me the location of all User directories. I still cant figure out which user is currently logged in but I can figure out all non-admin users which is very useful.
!include "NTProfiles.nsi"
!macro HandleUserProfiles
!define NTProfilePaths::IgnoreLocal
!ifndef __UNINSTALL__
${EnumProfilePaths} HandleUserProfile
!else
${EnumProfilePaths} un.HandleUserProfile
!endif
!macroend
!macro HandleUserProfile prefix
Function ${prefix}HandleUserProfile
Pop $R9
!ifndef __UNINSTALL__
# Copy files to user dir
SetOutPath "$R9\AppData\Roaming\Autodesk\Revit\Addins\2013" # $APPDATA = C:\ProgramData
FILE /r "${INSTALLFILEDIR}\Addins\Revit_2013\myAddin.addin"
!else
Delete "$R9\AppData\Roaming\Autodesk\Revit\Addins\2013\myAddin.addin"
!endif
# Continue Enumeration
Continue:
Push ""
Return
# Stop Enumeration
Stop:
Push "~" # Any value other than an empty string will abort the enumeration
FunctionEnd
!macroend
!insertmacro HandleUserProfile ""
!insertmacro HandleUserProfile "un."

NSIS - EnvVarUpdate overwrites system path when path is too long, is there a workaround?

Here is my simple code:
!include "EnvVarUpdate.nsh"
Outfile "text.exe"
Section
${EnvVarUpdate} $0 "PATH" "A" "HKLM" "C:\Program Files\something"
SectionEnd
I understand that the "A" argument means this should APPEND the last argument to system path. However, testing this revealed that it overwrote my Path variable. Further tests reveal this is because Path was too long (>1024 chars, per the tutorial).
Is there a "safe" way to append to Path then? I am looking for a function that will append if Path is short enough, otherwise do nothing and report an error, something of that sort. I'm wondering if a standard method of doing this already exists. Thanks!
We have encountered some problems with path modifications from NSIS installers due to the fact that the default string management is limited to 1024 bytes and that string manipulations involved in path modification is truncating strings to 1024 and that is sometimes braking workstation environment (especially in development hosts where many tools are installed). BTW, There are many nsis built setups in the wild that are suffering from this problem.
We are using some different code derived from the AddToPath function from Path manipulation but the problem stays similar.
The best workaround that we are using until now is by using the special build of NSIS that provides the large string support (of 8kB instead of 1 kB). That build is available in the special builds page of the NSIS wiki.
Can you try this?
Section
ReadEnvStr $0 PATH
StrCpy $0 "$0;C:\Program Files\something"
StrLen $1 $0
${if} $1 < 1024
${EnvVarUpdate} $0 "PATH" "A" "HKLM" "C:\Program Files\something"
${else}
messagebox mb_ok "error writing environment variable"
${endIf}
SectionEnd

rename file with the name of installer name in NSIS installer?

I'm working with NSIS installer. I need to change file defined in install path to the same installer name.
I try to use rename function like:
Rename "$INSTDIR\app.exe" "$INSTDIR\installname.exe"
but I need the installer name automatic.
Take a look at the constants, $EXEFILE is the filename, or $EXEPATH for the full path. If you want the name attribute you used in your source file, it is $(^Name)...
From FileFunc header you can combine GetExeName and GetFileName macros to get the installer's name:
!include "FileFunc.nsh"
OutFile test.exe
section main
${GetExeName} $R0
${GetFileName} "$R0" $R1
MessageBox MB_OK "My installer's exe is $R1"
sectionend
Now you can test it yourself.

Create more than 1 uninstaller in a NSIS Section

Can a NSIS Section create more than 1 uninstaller?
My installer can install plugins for 3 different versions of an Application - therefore theres 3 different directories where the installer will install the files.
In each of those directories I want to add an uninstaller file that will remove only the files in that directory.
Each of the 3 uninstall files are created within the same Section area, is this invalid? How can I get my script to create 3 uninstallers(if possible)?
The following Section only creates one uninstaller, the last one(Version 10 uninstaller):
Section "Install Plugin Files" MainSetup
CheckInstallVers8:
IntCmp $installVers8 1 InstallVersion8 CheckInstallVers9 InstallVersion8
CheckInstallVers9:
IntCmp $installVers9 1 InstallVersion9 CheckInstallVers10 InstallVersion9
CheckInstallVers10:
IntCmp $installVers10 1 InstallVersion10 MainInstallation InstallVersion10
InstallVersion8:
# install plugins...
SetOutPath $VERS8DIR
writeUninstaller "${APPNAME} Uninstall.exe"
GoTo CheckInstallVers9
InstallVersion9:
SetOutPath $VERS9DIR
writeUninstaller "${APPNAME} Uninstall.exe"
GoTo CheckInstallVers10
InstallVersion10:
SetOutPath $VERS10DIR
writeUninstaller "${APPNAME} Uninstall.exe"
SectionEnd
You can call WriteUninstaller as many times as you want but you should use the full path name (writeUninstaller "$VERSxDIR\${APPNAME} Uninstall.exe")
You did not post a full script so it is hard to tell what is wrong with the logic (You might want to use LogicLib.nsh so you can do {IF}s) but you should be able to "MessageBox debug" your way to the solution.
One thing you did not talk about that might be relevant is the uninstaller logic. If the 3 uninstallers all do the exact same task then this is not an issue but I'd expect at least a difference in the uninstaller registry registration.
There are two ways to deal with this:
Tag data to the end of the uninstaller (or a .ini in the same directory)
Use !system to call makensis.exe and generate uninstallers at compile time that you include as normal Files
A different solution that might be relevant for plugins in sub-directories is to use a component page in the uninstaller and only delete the uninstaller when all 3 plugins have been removed...

Resources