How to force ReadRegStr to read 32bit Node? - nsis

How to force NSIS read x32 tree of Uninstall registry key on x64 PC?
Tried everything.
SetRegView 32
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\XXX" "XXX"
Doesn't work. It reads
"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\XXX"
onInit, or other part of install, still nothing.
Used NSIS 3.03.

The WOW6432Node key is the 32-bit key.
Redirected keys are mapped to physical locations under Wow6432Node. For example, HKEY_LOCAL_MACHINE\Software is redirected to HKEY_LOCAL_MACHINE\Software\Wow6432Node. However, the physical location of redirected keys should be considered reserved by the system. Applications should not access a key's physical location directly, because this location may change. For more information, see Accessing an Alternate Registry View.
SOFTWARE\Microsoft\Windows\... in RegEdit on a 64-bit machine is the 64-bit view and you need SetRegView 64 to access it.

It is a bit counter intuitive, but you need to use 64-bit reg view instead.
To read from:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\XXX
Use the following line:
ReadRegStr $0 HKLM64 "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\XXX" "XXX"
or, you may use the following lines:
SetRegView 64
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\XXX" "XXX"

Related

How can I create a single NSIS script which will generate different installers based on an input parameter?

I have an application which has development, testing and live versions. I have a command procedure which currently creates 3 different versions of the installer, which can be installed on 3 separate computers.
What I would like to do would be to have one NSIS script which I pass in a parameter to, which will create one of the versions of the installer changing the name of the product and the installation folder. This will allow me to install all 3 versions on the same computer.
What I have tried so far is;
Function .onInit
Var /GLOBAL INSTALL_TYPE
${GetOptions} $CMDLINE "/t" $INSTALL_TYPE
${if} $INSTALL_TYPE == ""
StrCpy $INSTALL_TYPE "Live"
ReadEnvStr $R0 SYSTEMDRIVE
StrCpy $INSTDIR "$LOCALAPPDATA\Programs\MyComp\MyApp$INSTALL_TYPE\"
FunctionEnd
!define MUI_PRODUCT "FCDS-RECAP$INSTALL_TYPE"
OutFile "MyApp-$INSTALL_TYPEinstaller.exe"
One of the main errors I get has to do with MUI_PRODUCT and look similar to;
warning 6000: unknown variable/constant "INSTALL_TYPE.lnk" detected, ignoring (FullDeploymentUser.nsi:121)
warning 6000: unknown variable/constant "INSTALL_TYPE" detected, ignoring (FullDeploymentUser.nsi:124)
Two types of comments would be useful;
This is what you are doing wrong...
This is what you should be doing...
As always any help is appreciated.
MUI_PRODUCT is technically not an official NSIS define, some guy just invented it and used it in a guide.
All instructions starting with ! are preprocessor instructions, those and OutFile and File cannot be controlled by ${GetOptions} because they happen at compile time on your developer machine.
I don't really recommend this 3 in 1 installer solution, it is a bit complicated. It is much better to just create 3 different installers:
!ifndef APPTYPE
!error "APPTYPE not defined"
!endif
Name "MyApp ${APPTYPE}"
OutFile "MyApp ${APPTYPE} setup.exe"
InstallDir "$ProgramFiles\MyApp ${APPTYPE}"
Page Directory
Page InstFiles
Section
SetOutPath $InstDir
File /r "c:\myfiles\MyApp\${APPTYPE}\*"
SectionEnd
and then just generate them with makensis -DAPPTYPE=Beta myapp.nsi etc.
If you really want this 3 in 1 style then you need to use the macros in Sections.nsh to manipulate the sections so that only one of them is visible and active. You also need to mark the install somehow (.ini file?) so that your uninstaller also knows which install type it is uninstalling.

NSIS: Install a folder based on 32/64 bits

I'm working on a installer script that needs to install one of two folders based on the OS bits. The selection occurs fine so far but for some reason I only see one folder within the resulting installer.
The relevant sections are below:
;Windows 32 or 64 bit version
!include "x64.nsh"
Section "JRE 64 Bit" Section5
SectionIn RO
;Use the right java version
DetailPrint "JRE extraction..."
SetOutPath "$INSTDIR\${APPDIR}\jre"
File /a /r "${SrcDir}\..\..\jre\jre_64\jre\*.*"
DetailPrint "JRE extraction complete!"
SectionEnd
Section "JRE 32 Bit" Section6
SectionIn RO
;Use the right java version
DetailPrint "JRE extraction..."
SetOutPath "$INSTDIR\${APPDIR}\jre"
File /a /r "${SrcDir}\..\..\jre\jre_32\jre\*.*"
DetailPrint "JRE extraction complete!"
SectionEnd
Function .onInit
#Determine the bitness of the OS and enable the correct section
IntOp $0 ${SF_SELECTED} | ${SF_RO}
${If} ${RunningX64}
SectionSetFlags ${Section5} $0
SectionSetFlags ${Section6} ${SECTION_OFF}
${Else}
SectionSetFlags ${Section5} ${SECTION_OFF}
SectionSetFlags ${Section6} $0
${EndIf}
FunctionEnd
Both folders exists as there is no warning. But instead of seeing two folders (jre_64 and jre_32) I just see one jre folder within the installer.
Is this expected behavior? I'm using NSIS 2.51. The resulting instaler can be found here.
You can see the full script here.
I guess it's because of the delta compression, as the two jre directories should have quite similar contents. The structure when viewing using 7-Zip doesn't necessarily represent the internal structure of the installer, which seems to be quite opaque.
I tried to find a tool to "properly" unpack the installer (like innounp for Inno Setup), but without success. This confirms the NSIS installer structure should be really opaque.
Did you do some manual testing to determine if the installer works as expected in both cases?
The path used in File instructions are not stored in the installer (except for the last path component if it is a folder), it is used to find the files on your development system. As you probably know, SetOutPath sets the destination directory and decompilers can only display parts of that path (they cannot resolve custom variables) and you used just "jre" for both the 32-bit and 64-bit folders.
7-zip is not a full decompiler, it only does what is needed to find the destination path names and it does not understand that there are really two different jre folders selected by your if statements.
NSIS will only store identical files once, add SetDatablockOptimize off to the top of your script and your installer will probably double in size.

How to detect chrome version in NSIS?

My webapp need to depend on chrome browser, so when the app installs, i have to detect the chrome browser version in Nsis script.
I try to use the following script, but it does not work. The $R0 is empty string.
!define CHROME "\Software\Microsoft\Windows\CurrentVersion\Uninstall\Google Chrome"
ReadRegStr $R0 HKLM "${CHROME}" "UninstallString"
How to detect chrome version information in NSIS script ?
You should look into the current user settings instead of the local machine (or in addition to the local machine if the resulting string is empty):
ReadRegStr $R0 HKCU "${CHROME}" "UninstallString"
Also you should not have a backslash at the beginning of the key path. Did you noticed a warning during the script compilation?
ReadRegStr: registry path name begins with '\', may cause problems

Copy file over conditionally

I am trying to do the following in my NSIS script. I do not know NSIS, and I was just handed down a task to tweak something. The idea: if this is window8 take some .exe files from a different location to deploy onto the target machine:
So I start with getting the version:
ReadRegStr $WINVER HKLM \
"SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
in the list of files to install I do this:
;List of files to install
File file1.exe
File file2.exe
${If} StrCmp $WINVER '6.2'
File .\otherlocationSource\file1.exe
File .\otherlocationSource\file2.exe
${EndIf}
I'm getting an NSIS script compile error on the ${if}... line.
I'd appreciate any pointers as to what I'm doing wrong.
The ${If} macro uses StrCmp internally, the syntax is ${If} $WINVER == "6.2" but you really should use WinVer.nsh to do the version check. (You can grab the version values from SVN if your local copy does not support Win8)
And for a version check like this, unless it is Win8 specific you should have logic similar to "if $major > 6 or ($major == 6 and $minor >= 2)" so it also works on Win9 etc

NSIS Identifying multiple uninstallers

I have multiple instances of a program and each has its own install directory with its own copy of the uninstaller. The installer has a field called "$instance" entered by the user which is recorded in the registry like this:
HKLM "SOFTWARE\#vendor.name#\#product.name# #product.version#\installs\$instance"
which works fine. This key contains the root path of the install.
I would like to uninstall the instance of the program that corresponds to the uninstaller that is executed but the Uninstall section does not retain the variable "$instance" that the user entered at install time.
Any ideas?
Example:
Section Uninstall
; THIS does not display the instance name. :(
MessageBox MB_OK "$instance"
SectionEnd
You can store custom data at the end of the uninstaller.exe without breaking the CRC check, or alternatively store it in a .ini in the same directory as the uninstaller (I do this all the time, just name the ini file "uninstaller.dat" or something like that so users don't mess with it)

Resources