- NSIS Discussion
- Testing for regkey (not value) existence
Archive: Testing for regkey (not value) existence
banaman8d
18th August 2003 19:37 UTC
Testing for regkey (not value) existence
How I can script for the existence of a registry key.
It would be better if there is an easier way to find this information. Because this is ridiculously inefficient.
; takes the root, subkey, and keyname name as arguments on the stack.
; It pushes onto the stack, 'exists' or
; otherwise depending on outcome of test.
Function KeyExists
Exch $R0 ;keyname
Exch ; swap keyname and subkey
Exch $R1 ;subkey
Exch 2 ; swap subkey and key root
Exch $R2 ;root
Push $R3 ;an index
Push $R4 ;stores keyname
StrCpy $R3 "0" ; initialize a counter
nextkey:
EnumRegKey $R4 HKLM "$R1" $R3
IfErrors notexists
StrCmp $R4 "" notexists
StrCmp $R4 $R0 exists
IntOp $R3 $R3 + "1"
Goto nextkey
notexists:
Push ""
Exch 5
Goto finish
exists:
Push "exists"
Exch 5
Goto finish
finish:
Pop $R0
Pop $R4
Pop $R3
Pop $R2
Pop $R1
FunctionEnd
Vytautas
19th August 2003 01:12 UTC
I have created a similar function/macro check my archive page.
Hope it helps you.
Vytautas
banaman8d
19th August 2003 16:17 UTC
Did you test that macro?
With the 2 beta 4 NSIS, I get a compilation error on line 5 of the macro when I give it the following:
!insertmacro "HKLM" "Software\Microsoft\Updates\Windows Server 2003\SP1" "KB823980"
The error is:
Invalid command: LoopReg_Software\Microsoft\Updates\Windows
The spaces create an invalid label, but it is a perfectly legal key.
I have attached a fix for the script...
but in order to workaround I needed to make the jumps relative to avoid naming problems.
Afrow UK
19th August 2003 16:41 UTC
Try placing quotes "" around the jump-to's (not the labels) inside the macro script.
They should be on just in case anyway.
-Stu
Afrow UK
19th August 2003 16:43 UTC
!macro KeyExists ROOT MAIN_KEY KEY
Push $R0
Push $R1
StrCpy $R1 "0"
LoopReg_${MAIN_KEY}${KEY}:
EnumRegKey $R0 "${ROOT}" "${MAIN_KEY}" $R1
StrCmp $R0 "" "NotFoundReg_${MAIN_KEY}${KEY}"
IntOp $R1 $R1 + 1
StrCmp $R0 ${KEY} 0 "LoopReg_${MAIN_KEY}${KEY}"
FoundReg_${MAIN_KEY}${KEY}:
Push "1"
Goto "FinishFindReg_${MAIN_KEY}${KEY}"
NotFoundReg_${MAIN_KEY}${KEY}:
Push "0"
FinishFindReg_${MAIN_KEY}${KEY}:
Exch 2
Exch
Pop $R1
Pop $R0
!macroend
-Stu
banaman8d
19th August 2003 18:43 UTC
I realize that you want to use labels because it is more resilient to modifications in the code, but this macro cannot be used in certain situations because of the uniqueness (or lack of) of the keys.
For instance:
!insertmacro KeyExists A_ROOT A_MAINKEY A_KEY
; Do something like ExecWait that should modify the key
...
; And this will have duplicate labels...
!insertmacro KeyExists A_ROOT A_MAINKEY A_KEY
I agree with using labels in the name of maintainability, but not at the expense of the efficacy of the macro. If I use the above, I have to remember that it won't work if I use it twice in the same function for the same key. For a small macro like this one, doesn't it make more sense to relax the 'rule' for the benefit of the functionality?
pengyou
19th August 2003 19:43 UTC
You could use ${__LINE__} to generate unique labels in a macro.
Define the macro like this:
!macro myMacro UNIQUE_ID BLAH_1 BLAH_2
...
StrCmp ${BLAH_1} ${BLAH_2} Label_A_${UNIQUE_ID}
...
...
Label_A_${UNIQUE_ID}:
...
...
!macroend
Then use the macro like this:
!insertmacro myMacro ${__LINE__} $0 $1
banaman8d
19th August 2003 20:12 UTC
Thank you for that insight... not only does it solve the uniqueness problem, but it also gives the user the line number of the macro if compilation fails.
Afrow UK
19th August 2003 20:51 UTC
Thanks pengyou - that will solve problems with a lot of macros (when wanting to be used multiple times)
Edit: Doesn't work. :(
-Stu
pengyou
19th August 2003 21:12 UTC
Originally posted by Afrow UK
Edit: Doesn't work. :(
Could you give some more detail about what does not work? I have used this idea several times and it never fails to work for me.
Are you trying it in single-file scripts or in scripts which use !include. If you are trying to use it in scripts comprising several source files, you may need to extend the idea slightly (eg combine the line number and the source file name?).
Vytautas
20th August 2003 03:56 UTC
pengyou could you attach a working sample of label commands using {__LINE__}, cos I could not get it to work either.
Mean while I have updated by archive macro as suggested by banaman8d and it seems to work OK.
Vytautas
pengyou
20th August 2003 11:30 UTC
Vytautas,
Here is a simple example which works on my Win98SE system. I have included an extract from the compiler output which shows the line number being used to generate unique label names when the macro is "inserted".
Perhaps you are using a different version of makensis.exe ?
banaman8d
20th August 2003 13:21 UTC
pengyou,
Are you using NSIS 2beta4? I compiled and ran the executable generated by your script and everything appears to work OK.
But I am using 2beta4.
When did ${__LINE__} get introduced?
pengyou
20th August 2003 13:49 UTC
Yes, I am using NSIS 2.0b4 with the 11 August 2003 (19:44 GMT) CVS snapshot.
According to the NSIS Changelog ${__LINE__} was introduced on 12 June 2003 (15:09)
Afrow UK
20th August 2003 14:23 UTC
Pengyou means to put ${__LINE__} in the !insertmacro, not in the actual labels themselves.
Placing it in labels means that e.g.
Goto line${__LINE__}
line${__LINE__}:
will be
Goto line1
line2:
-Stu
deguix
20th August 2003 16:09 UTC
Use ${__LINE__} in a variable:
StrCpy$0 ${__LINE__}
>Goto line$0
MessageBox MB_OK "!"
>line$0:
So you can use it in labels, am I right?
Afrow UK
20th August 2003 16:28 UTC
Yes, but that would use up a variable which shouldn't be done (where possible)
But indeed, that is the answer.
I think that NSIS compiler should somehow add numbers autommaticaly to the macro labels before inserting them.
-Stu
banaman8d
21st August 2003 16:07 UTC
That would be great if !insertmacro expanded labels to the line of the !insertmacro statement automatically. However, that may break existing scripts if they were to use macros that use external labels. Like the following:
!macro For Init Cmp Inc
Push $R0
StrCpy $R0 ${Init}
next:
IntCmp $R0 ${Cmp} 0 0 last
!macroend
!macro ForEnd
IntOp $R0 $R0 + ${Inc}
Goto next
last:
Pop $R0
!macroend
Used like:
...
!insertmacro For 1 10 1
DetailPrint "$R0"
!insertmacro ForEnd
...
This is a bad way to write a macro like a for loop because you are limited to 1 per function, but you get the idea.
A good compromise is that !insertmacro expands all occurances of ${__EXPANDLINE__} to the line of the !insertmacro. This changes the line:
!insertmacro ${__LINE__} arg1 ...
to,
!insertmacro arg1 ...
and you use ${__EXPANDLINE__} explicitly in the macro labels (if you want to).