Reading registry key value in NSIS fails - nsis

I already posted a similar question (NSIS - check if registry key value exists) and the solution to that question worked perfectly:
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports" "NUL:"
And then:
${If} ${Errors}
#and so on
I do the same thing three more times in the script, reading different registry values and all attempts but the last one are successful:
ReadRegStr $3 HKLM "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers\SomePrinter" "Name"
This always returns an error.
What should I do differently?
The first time I read a registry value, I use $0 to store the return vale. Then the second time $1 and then $2 and $3.
As I said, all work except for the last one. Does it have to do with the type of registry key I'm reading or should I use a different variable for the return value? I have tried other variables, but so far nothing has worked.
Thanks for help and tips!

The problem with
ReadRegStr $3 HKLM "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers\SomePrinter" "Name"
is that you specify the root twice:
HKLM
HKEY_LOCAL_MACHINE\...
Remove the HKEY_LOCAL_MACHINE from the sub key name and it should be OK. If you need to access another part of the registry, change the 2 parameter of ReadRegStr as described in WriteRegExpandStr manual section:
HKCR for HKEY_CLASSES_ROOT
HKLM for HKEY_LOCAL_MACHINE
HKCU for HKEY_CURRENT_USER
HKU for HKEY_USERS
HKCC for HKEY_CURRENT_CONFIG
HKDD for HKEY_DYN_DATA
HKPD for HKEY_PERFORMANCE_DATA
SHCTX for SHELL_CONTEXT

Related

NSIS File Associations change in Windows 7

I have a requirement to (force) change the file association for a particular file type (extenison ".theext" ) to open with "myapp.exe" when installing an app using NSIS.
I've read a few suggestions of how to achieve this, so currentky this is what I have in my NSIS script:
DeleteRegKey HKCR ".theext"
DeleteRegKey HKLM ".theext"
DeleteRegKey HKCU ".theext"
WriteRegStr HKCR ".theext" "" "theextfile"
WriteRegStr HKCR "theextfile" "" "My App Document"
WriteRegStr HKCR "theextfile\DefaultIcon" "" "$INSTDIR\${EXENAME}.exe,0"
WriteRegStr HKCR "theextfile\shell\open\command" "" '"$INSTDIR\${EXENAME}.exe" "%1"'
WriteRegStr HKCR "theextfile\shell\print\command" "" '"$INSTDIR\${EXENAME}.exe" /p "%1"'
WriteRegStr HKLM "Software\RegisteredApplications" "${EXENAME}" "$INSTDIR\${EXENAME}.exe"
WriteRegStr HKCU "Software\RegisteredApplications" "${EXENAME}" "$INSTDIR\${EXENAME}.exe"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.theext\OpenWithList" "a" "$INSTDIR\${EXENAME}.exe"
To test this, I set the file assoc using WIndows 7 Explorer to GVIM.exe.
Since doing this, every time I run the installer, Windows 7 still opens the file on double click using GVim, and not "MyApp.exe".
But when I check the file associatin as follows, all seems fine:
ftype | findstr /i theext
Gives:
theextfile="C:\Program File (x86)\My App\myapp.exe" "%1"
You are doing everything you are supposed to do and if the extension is not already registered by somebody else you will become the default. You are not really supposed to delete the old keys first though (it can screw up the system but it will never help you become default). Forcing something is evil, the user is supposed to be in control.
Because people forced this in the past Microsoft starting making it harder to change the default. The undocumented FileExts key stores the users chosen default in the UserChoice sub-keys. In newer versions of Windows (8+?) the default is verified with some secret hash so you cannot override it.
The IApplicationAssociationRegistration interface does not work in newer version of Windows but it might work in Windows 7:
!include Win\COM.nsh
!include WinCore.nsh
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationAssociationRegistration} ${IID_IApplicationAssociationRegistration} r0 ""
${If} $0 P<> 0
${IApplicationAssociationRegistration::SetAppAsDefault} $0 '("MyApp", ".myext", ${AT_FILEEXTENSION})'
${IUnknown::Release} $0 ""
${EndIf}
In Windows 8 all you can do is launch the generic UI:
!include Win\COM.nsh
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ApplicationAssociationRegistrationUI} ${IID_IApplicationAssociationRegistrationUI} r0 ""
${If} $0 P<> 0
${IApplicationAssociationRegistrationUI::LaunchAdvancedAssociationUI} $0 '("Wordpad")' ; Replace with your name from the RegisteredApplications key
${IUnknown::Release} $0 ""
${EndIf}
In Windows 10 even this is gone, it will just display a toast telling the user to change their settings if you call LaunchAdvancedAssociationUI.
ftype does not know the true default, the default is only known when Windows actually runs the association code in the shell. IApplicationAssociationRegistration::QueryCurrentDefault is better at guessing the default but even it can fail if the default is actually a COM shell extension that overrides the default.

NSIS uninstaller doesn't delete files/folders

I'm writing a NSIS installer for one of the apps that the company I work for uses internally, the install process works fine, with no problems all the REG keys are created, and so are the files folders and services, that the App uses. For some reason I can't understand, the uninstall process doesn't work's.
The services created by the app are deleted and so are the Registry keys, the most simple part, the files themselves, I can't delete them through the uninstaller!
#Includes
!include "x64.nsh"
#Defines and Installer Properties
Outfile "ESTvnc Installer.exe"
Name ESTvnc
Icon "${NSISDIR}\contrib\graphics\icons\VNCON.ico"
#Detect OS Version
Function .onInit
StrCpy $instdir $PROGRAMFILES
${If} ${RunningX64}
StrCpy $instdir $PROGRAMFILES32
${EndIf}
FunctionEnd
section
SetShellVarContext all
CreateDirectory $instdir\EST\ESTvnc
setOutPath $instdir\EST\ESTvnc
File /r installfiles\*
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\ESTvnc\" \
"DisplayName" "ESTvnc"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\ESTvnc"\
"UninstallString" "$instdir\EST\ESTvnc\uninstaller.exe"
writeUninstaller $instdir\EST\ESTvnc\uninstaller.exe
ExecWait '"$instdir\EST\estvnc\estvnc.exe" -install'
sectionEnd
section "Uninstall"
SetShellVarContext all
SimpleSC::StopService "ESTVNC" 1 30
pop $0
SimpleSC::StopService "ESTVNCSR" 1 30
pop $0
SimpleSC::RemoveService "ESTVNC"
SimpleSC::RemoveService "ESTVNCSR"
RMDir /r "$instdir\EST\ESTvnc"
Delete $instdir\EST\ESTvnc\uninstaller.exe
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\ESTvnc"
sectionEnd
In the uninstaller, $instdir is the directory the uninstaller is in!
Either place the uninstaller in $instdir and delete $instdir\EST\ESTvnc or if you want to keep it in $instdir\EST\ESTvnc, delete $instdir...

Checking for Registry in NSIS

I'm using NSIS to make an executable for a project I'm doing in Visual C++ 2012 Express. Because I'm a beginner, I started with the Setup Wizard in HM NIS Edit.
I'm trying to bundle the Visual C++ 2012 Redistributable with my program, but every time the installer is re-ran, the Redistributable pops up with a "Repair" & "Remove" option, and that looks annoying.
So I decided to write a little bit of NSIS script, and this is the start of the script so far:
Var STR
Section CheckForReg
ClearErrors
ReadRegDWORD $0 HKLM "SOFTWARE\Classes\Installer\Dependencies\{8e70e4e1-06d7-470b-9f74-a51bef21088e}" "Version"
ifErrors 0 Blank
StrCpy $STR "$INSTDIR\vcredist_x86.exe"
GoTo End
Blank:
StrCpy $STR ""
End:
SectionEnd
This piece is called at the very start of the script, and the global variable STR is applied to:
!define MUI_FINISHPAGE_RUN $STR
Shortly after.
Obviously this is a really silly way to do it, but I don't need too much out of it.
The issue is that the CheckForReg always thinks the registry doesn't exist, and doesn't move to the label Blank. As a note, I'm manually checking the registry every time, and the registry entry looks like:
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Dependencies\{8e70e4e1-06d7-470b-9f74-a51bef21088e}]
"Version"="11.0.51106.1"
"DisplayName"="Microsoft Visual C++ 2012 Redistributable (x86) - 11.0.51106"
So the question is: Where am I going wrong with this? It looks very simple, but obviously I have something backwards.
-- Removed Code Dump
You can only read DWORDs with ReadRegDWORD!
!include LogicLib.nsh ; So we don't have to use all these labels
StrCpy $STR ""
ReadRegStr $0 HKLM "SOFTWARE\Classes\Installer\Dependencies\{8e70e4e1-06d7-470b-9f74-a51bef21088e}" "Version"
${If} $0 == ""
StrCpy $STR "$INSTDIR\vcredist_x86.exe"
${EndIf}

how can i make my installer to check for invalid folder installation?

.Actually i have installed different version of the software in the same computer so want to check the folder for both the version when user proceed for third version of installation. i am trying to use loop but the the installer is not working.Thanks in advance.
I have already 2 versions of same software installed in the same computer .I want when i will install the third version the script should check the path and it should not allow user to install in the same path in which previous two versions are already installed
Function .onVerifyInstDir
nsArray::Set array 1.6
nsArray::Set array 1.7
nsArray::Set array 1.8
nsArray::Length array
Pop $R0
;DetailPrint `array length: $R0`
StrCpy $R1 0
${DoWhile} $R1 < $R0
nsArray::Get array $R1
Pop $R2
StrCpy $tempregistry "$(^Name)_$R2"
;DetailPrint `MyArray2[$R1] is $R2`
ReadRegStr $path HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstal\$tempregistry""InstallLocation" ;fetching installed location
${If} $path == ""
${Else}
strCmp $path $INSTDIR 0 pathGood
;Abort
IntOp $R1 $R1 + 1
${EndIf}
${Loop}
PathGood:
FunctionEnd
Here are the steps
Store ur product name or ur registry entry in a variable.
Store the path to be installed in a variable eg $path
Inside a loop check for the registry entry.
ReadRegStr $pdt HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\productname
If found,retrieve the value of the installed location and store it in a variable;
eg $path1
ReadRegStr $path1 $pdt "installed location"
else proceed
${if} $path == $path1
messagebox mb_ok "Another version already installed in the path"
${else}
proceed
${endif}

NSIS: environment variable created doesn't work

I am creating a Env Variable and then appending it to the PATH variable in my NSIS installer script on Win7 - 64 bit.
Push "MyPath"
Push "D:\MyFolder\bin;D:\MyFolder\lib"
Call WriteEnvStr
Push "%MyPath%"
Call AddToPath
Now after installation I can see both the variable in cmd prompt
MyPath=D:\MyFolder\bin;D:\MyFolder\lib
Path=%MyPath%;<my existsing path>
But any exe/dll from are not found at run time.
If I run the cmd prompt as Administrator and then run exe, it runs fine.
It also works if I run exe directly as an Administrator.
Also interesting is that if I open Environment editor, double click on MyPath variable and click OK (without changing anything), my exe's run fine without running as Administrator.
And now if I check Path in cmd prompt, MyPath variable is substituted
MyPath=D:\MyFolder\bin;D:\MyFolder\lib
Path=D:\MyFolder\bin;D:\MyFolder\lib;<my existsing path>
I tried to add "Call EnvVarUpdate" after creating the env variable but it doesn't work.
I am using NSIS Unicode version 2.46.3
Your chances of adding/modifying the path without losing data in path by truncating it would be much greater by using the registry.
ReadRegStr $0 HKCU "Environment" Path
StrCpy $1 "D:\MyFolder\bin;D:\MyFolder\lib"
StrCpy $2 "$0;$1"
WriteRegStr HKCU "Environment" Path "$2"
If your system has an AUTOEXEC.BAT file then any PATH setting in AUTOEXEC.BAT will also be appended to the %PATH% environment variable. This is to provide compatibility with old installation routines which need to set the PATH. All other commands in AUTOEXEC.BAT are ignored however. And this is more or less obsolete anyway.
But we could just continue with your method however just try a different means of acomplishing your goal. I have not tested this but you can try something similar to this:
StrCpy $R0 "MYPATH"
StrCpy $R1 "D:\MyFolder\bin;D:\MyFolder\lib"
System::Call `Kernel32::SetEnvironmentVariable(t"$R0",t"$R1")`
Now include your new variable in the path like the following:
ReadEnvStr $R0 COMSPEC
ReadEnvStr $R1 MYPATH
ExecDos::Exec /TOSTACK `"$R0" /c "SetX PATH=%PATH%;$R1 -m"`
You can now easily change that one variable %MYPATH% at any time in the future and the PATH will reflect the new value.
${EnvVarUpdate} $0 "PATH" "A" "HKLM" "C:\Program Files\Java\jre6\bin"
StrCpy $R0 "$0"
System::Call 'Kernel32::SetEnvironmentVariableA(t, t) i("PATH", R0).r2'
ReadEnvStr $R0 "PATH"
ExecWait "$INSTDIR\tmp\batchfile.bat

Resources