Archive: Testing for regkey (not value) existence


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


I have created a similar function/macro check my archive page.

Hope it helps you.

Vytautas


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.


Try placing quotes "" around the jump-to's (not the labels) inside the macro script.
They should be on just in case anyway.

-Stu



!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

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?


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


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.


Thanks pengyou - that will solve problems with a lot of macros (when wanting to be used multiple times)

Edit: Doesn't work. :(

-Stu


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?).

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


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 ?


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?


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)


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


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?

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


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).