Archive: ReadRegStr maximum lenght?


ReadRegStr maximum lenght?
Dear all,

I am trying to add a check to see if the software is installed or not. If it is installed the installation should abort, if it is not installed the installation should continue as planned.

I currently have this:

; Check to see if already installed
Section -Run
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48} InstallLocation
IfFileExists $R0 +1 NotInstalled
MessageBox MB_OK "Driver is already installed, installer will continue."
Quit

NotInstalled:
MessageBox MB_OK "Driver is not already installed, installer will continue."
Quit
SectionEnd
This does not work, register (and its key value) is not recognized.. It simply says that it is not found (but it is definitly there)

However if I try:
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\ ProgramFilesDir
or
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Themes InstallTheme
It does work properly.

I also tried:
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\AVG InstallLocation
Which doesn't work either.

Is there a maximum lenght of the ReadRegStr? Can I only enter so many subfolders?

Thanks in advanced,
Ruud

If there was a maximum length of 90 characters I'm sure you would have heard about it already, so no that is not your problem. Is it perhaps because you are running on Windows x64 and you haven't disabled registry redirection with SetRegView 64?

Stu


Thanks for your quick reply.

All my test computers are 32bit, so that can't be the problem.
I tried it so far on W7, Vista, and XP (all 32bit). - None seem to work.

Thanks for the help,
Ruud


Here is the full code, I'm currently using.. Maybe I am missing something (but then the others shouldn't work either, right?)

; --- MUI 1.66 compatible
!include "MUI.nsh"

; --- General Information
Name "App Name"
BrandingText "App Branding Text"
OutFile "..\OutputFile.exe"
InstallDir "$TEMP\Folder"

; --- Define images and include pages
!define MUI_ABORTWARNING
!define MUI_WELCOMEFINISHPAGE_BITMAP "USB.bmp"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP "HEADER.bmp"
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "Dutch"

; --- Include Files
Section -Files
SetOutPath "$INSTDIR"
File "USB.bmp"
File "HEADER.bmp"
anotherFile
anotherFile
etc..
..
SectionEnd

; --- Check to see if already installed, then run
Section -Run
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}" "InstallLocation"
IfFileExists $R0 +1 NotInstalled
MessageBox MB_OK "Driver is already installed, installer will continue."
Quit

NotInstalled:
MessageBox MB_OK "Driver is not already installed, installer will continue."
Quit
SectionEnd

The limit is probably 1024, try running Process Monitor see what the issue is


Thank you for your reply.

This is what Process Monitor says:

RegOpenKey
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}
SUCCESS
Desired Access: Read

RegQueryValue
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}\InstallLocation
SUCCESS
Type: REG_SZ, Length: 98, Data: C:\Program Files\ProgramDir

RegQueryValue
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}\InstallLocation
SUCCESS
Type: REG_SZ, Length: 98, Data: C:\Program Files\ProgramDir

RegCloseKey
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}
SUCCESS

CreateFile C:\Program Files\ProgramDir
SUCCESS
Desired Access: Read Data/List Directory, Synchronize, Disposition: Open, Options: Directory, Synchronous IO Non-Alert, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened

CloseFile C:\Program Files\ProgramDir
SUCCESS
Then it continue with a lot of keyboard layouts..

So it seems like it actually does recognize / read the key.. But somehow my program does not recognize it?

Edit01:
Btw I changed the real program directory to ProgramDir. Thats why it shows "length: 98", its the length of the orignal program dir.

Check the read value with a MessageBox.

Edit: Is there a reason you call Quit in both cases? Is that on purpose?

Stu


The registry entry holds the name of the directory so you need to check that the directory exists:

IfFileExists "$R0\*.*" +1 NotInstalled

or else check that a particular file exists in that directory

IfFileExists "$R0\somefile.exe" +1 NotInstalled


Thank you guys for all the help.
Thank you pengyou, that seems to do the trick.

Originally posted by Afrow UK
Is there a reason you call Quit in both cases? Is that on purpose?
Currently this how my code will look. I used the message-boxes to test if the function works, now I substituted them to run an .exe

; --- Check to see if already installed
Section -Run
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48} InstallLocation
IfFileExists "$R0\*.*" +1 NotInstalled
ExecWait "$INSTDIR\InstallAll\Setup.exe"
SetAutoClose true
Quit

NotInstalled:
ExecWait "$INSTDIR\install.exe"
SetAutoClose true
Quit
SectionEnd
I tested it without calling "Quit", but then the code automatically continues to NotInstalled.
Installer detects software is already installed.
Starts running InstallAll\Setup.exe
InstallAll\Setup.exe is finished
Automatically continue and start running NotInstalled (thus running install.exe).
But all I need now is, if already installed run programA.. if not installed run programB.
The docs doesn't say "Quit" is needed, so this issue might occur due to my lack of experience with NSIS. Am I missing something?

Thanks,
Ruud

If you need to Quit your installation after then that is fine. You could also just use LogicLib:

${If} ${FileExists} $R0\*.*
...
${Else}
...
${EndIf}
SetAutoClose true
Quit
Stu

Hi guys...
Thanks for all the help, but I might have replied a bit to early.

It is still not working probably, the following is going on:

If using:

${If} ${FileExists} $R0\*.*
or
IfFileExists "$R0\*.*" +1 NotInstalled

It always runs programB (the program that runs when nothing is detected)

If using:
${If} ${FileExists} $R0
or
IfFileExists "$R0" +1 NotInstalled

It always runs programA (the program that runs when something is detected)

Currently my code looks like this (Thanks to the suggestion of Afrow UK)
; --- Check to see if already installed
Section -Run
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48} InstallLocation
${If} ${FileExists} $R0\*.*
ExecWait "$INSTDIR\programA\Setup.exe"
${Else}
ExecWait "$INSTDIR\programB\install.exe"
${EndIf}
SetAutoClose true
Quit
SectionEnd


Maybe I should go for reading a different registry entry? I tried "UninstallString", which generates similair results.

Thanks,
Ruud

What is the stored value?

Stu


Thanks for your help Afrow UK.

Here is a screen of the whole register:
http://www.uploadup.com/dt-4W8F.jpg


I submitted a post a few seconds ago with a screen of the register, but this one has to be moderated so here is a quick overview:

DisplayName --- REG_SZ --- 32bit Driver Install
InstallLocation --- REG_SZ --- C:\Program Files\ ..
InstallSource --- REG_SZ --- E:\Autoinstall\..
UninstallString --- REG_EXPAND_SZ --- MsiExec.exe /I..
Again when using "$R0\*.*" or using "$R0" it claims always to be installed (or not installed).

I added a function to check if its 32 or 64 bit, (which seems to properly function - not tested on 64bit yet), here is the full code:

; --- Install to the correct directory on 32 bit or 64 bit machines. 
Section -Run
IfFileExists $WINDIR\SYSWOW64\*.* Is64bit Is32bit
Is32bit:
MessageBox MB_OK "32 bit"
SetRegView 32
GOTO Installation32Bit

Is64bit:
MessageBox MB_OK "64 bit"
SetRegView 64
GOTO Installation64Bit

; --- Check to see if already installed, then run install.
Installation32Bit:
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{32bit} UninstallString
IfFileExists "$R0\*.*" Is32Installed Is32NotInstalled
Is32NotInstalled:
MessageBox MB_OK "Not Installed"
ExecWait "$INSTDIR\SoftwareA\install.exe"
SetAutoClose true
GOTO End32Bitvs64BitCheck
Is32Installed:
MessageBox MB_OK "Installed"
ExecWait "$INSTDIR\SoftwareB\Setup.exe"
SetAutoClose true
GOTO End32Bitvs64BitCheck

Installation64Bit:
ReadRegStr $R1 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{64bit} UninstallString
IfFileExists "$R1\*.*" Is64Installed Is64NotInstalled
Is64NotInstalled:
MessageBox MB_OK "Not Installed"
ExecWait "$INSTDIR\SoftwareA\install.exe"
SetAutoClose true
GOTO End32Bitvs64BitCheck
Is64Installed:
MessageBox MB_OK "Installed"
ExecWait "$INSTDIR\SoftwareB\Setup.exe"
SetAutoClose true
GOTO End32Bitvs64BitCheck

; --- When finished quit.
End32Bitvs64BitCheck:
Quit
SectionEnd


The code above always claims that the softare is installed.
UninstallString or InstallLocation generate same, incorrect, results (both using "$R0\*.*" or using "$R0").

Note:
I changed the string in the above code for the registry-entry, so the post doesn't rip open the forum design. If needed, here they are:
{32bit} = {BF61699A-6D79-4A97-B879-7A890E5A9A48}
{64bit} = {51C64AFF-0180-47E0-A535-2D99EBC10F09}

When I asked what the value was I meant what is the path stored. Put in a MessageBox to display the value of $R0. I didn't want a screenshot from the registry editor! Plus you have blanked out half the values so it's not much help to us anyway!

As for 32/64 you should use the macro in x64.nsh (${If} ${RunningX64}). Also you need to use SetRegView 64 if the registry key isn't under Wow6432Node on 64-bit Windows (this has no effect/is ignored on 32-bit Windows).

There are only two possible reasons that your code isn't working:
1. The path is wrong
2. The path has no read access

Does the path end with a backstroke? Does it have any whitespace on the end? Can you open up cmd and cd to the directory it specifies?

Stu


I only blanked out 4 values (the one with the line through it), the rest are all empty.

Full path (direct copy-paste from the registry):
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}

$RO - doesn't print anything.
But using the following it does work / does print something..
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Themes

Using the following (doesn't matter what inside it) doesn't work..
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\

Thats why my initial quetion about path length.
But it might be something with permissions; Do I need special permission to acces the Uninstall path? How can I check for read access?

Reg-Values

DisplayName --- REG_SZ --- Driver 32bit Driver Install
InstallLocation --- REG_SZ --- C:\Program Files\Driver\
InstallSource --- REG_SZ --- E:\Autoinstall\Driver\
UninstallString --- REG_EXPAND_SZ --- MsiExec.exe /I{BF61699A-6D79-4A97-B879-7A890E5A9A48}
ProcessMonitor
-- When computer with program NOT installed
RegOpenKey
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}
NAME NOT FOUND
Desired Access: Read
-- When computer with program installed
RegOpenKey
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}
SUCCESS
Desired Access: Read

RegQueryValue
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}\UninstallString
SUCCESS
Type: REG_EXPAND_SZ, Length: 106, Data: MsiExec.exe /I{BF61699A-6D79-4A97-B879-7A890E5A9A48}

RegQueryValue
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}\UninstallString SUCCESS Type: REG_EXPAND_SZ, Length: 106, Data: MsiExec.exe /I{BF61699A-6D79-4A97-B879-7A890E5A9A48}

RegCloseKey
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BF61699A-6D79-4A97-B879-7A890E5A9A48}
SUCCESS

CreateFile C:\Users\User\AppData\Local\Temp\Driver\x86\x86Inf\i386\MsiExec.exe \I{BF61699A-6D79-4A97-B879-7A890E5A9A48}\
PATH NOT FOUND
Desired Access: Read Data/List Directory, Synchronize, Disposition: Open, Options: Directory, Synchronous IO Non-Alert, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a
So it seems like it is working properly according to process monitor.
But why does it try to create a file at the UnistallString? It only has to check if the value exist or not, right?

EDIT01:
Originally posted by Afrow UK
Can you open up cmd and cd to the directory it specifies?
Haven't tried this, about to try it.

UPDATE - SOLVED
So my findings conclude that in this case "CreateFile" is the issue.
"CreateFile" seems to be creating a temp file to check if folder really exist.

ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\etc.. REGISTRYKEY
IfFileExists "$R1\*.*" Installed NotInstalled
NotInstalled:
MessageBox MB_OK "Not Installed"
GOTO EndInstall
Installed:
MessageBox MB_OK "Installed"
GOTO EndInstall

The following happens when using "InstallLocation:
1. It read the registry, trying to find the key you identified
2. It stores the value into a string
3. It reads the string
4.a Is there a value in the string? Yes continue 5a
4.b No value in string? Continue 5b
5.a. Create a temp file at location of string.
SUCCES! Go to "Installed".
5.b. Create a temp file at C:/.
SUCCES! Go to "Installed".
The following happens when using "UninstallString:
1. It read the registry, trying to find the key you identified
2. It stores the value into a string
3. It reads the string
4.a Is there a value in the string? Yes continue 5a
4.b No value in string? Continue 5b
5.a. Can't access temp folder, can't create a temp file.
FAIL! Go to "NotInstalled"
5.b. No file to access, can't create a temp file.
FAIL! Go to "NotInstalled"
First it tries to find the path gathered from the registry string. Then it tries to create a temp file in that path. This seems to defeat the whole purpose of "IfFileExist". (The fact that the folder exist doesn't necessarily mean that it should be accessible / wirable).

I'm using the following code, which seems to be doing the trick:
ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\etc.. REGISTRYKEY
${If} $R0 == "Value of REGISTRYKEY"
MessageBox MB_OK "Program Installed"
GOTO EndInstall
${Else}
MessageBox MB_OK "Program Not Installed"
GOTO EndInstall
${EndIf}
${EndIf}

The following happens when using this:
1. It read the registry, trying to find the key you identified
2. It stores the value into a string
3. It reads the string
4.a Is string equal to required value? Yes
Display Box
4.b Is string equal to required value? No
Display Box
I am not sure if this is the right way to do it, but it does work.
This will not work if you don't know the value of they key, or the key is not static.