Search code examples
offsetnsis

Weird behaviour of offset


I have the following code

ClearErrors
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Office\ClickToRun\Configuration" "ProductReleaseIds"
IfErrors done                       ;+19 if error
${StrLoc} $R1 $R0 "365" ">"
    StrCmp $R1 "" next 0            ;+8 if substring is not found
    ReadRegStr $R1 HKLM "SOFTWARE\Microsoft\Office\ClickToRun\Configuration" "Platform"
        ${If} $R1 = "x86"
            StrCpy $R1 "365x32"
        ${Else}
            StrCpy $R1 "365x64"
        ${EndIf}
        Goto found_${ID}
next: ${StrLoc} $R1 $R0 "2019" ">"
    StrCmp $R1 "" done 0            ;+8 if substring is not found
    ReadRegStr $R1 HKLM "SOFTWARE\Microsoft\Office\ClickToRun\Configuration" "Platform"
        ${If} $R1 = "x86"
            StrCpy $R1 "2019x32"
        ${Else}
            StrCpy $R1 "2019x64"
        ${EndIf}
        Goto found_${ID}
done: ClearErrors

Even if no errors/warnings rised during code compiling, the code behaviour wasn't as expected. After 2 hours of "imaginative" debugging, I understood the cause of the weird behaviour I was experiencing.

In the code at the end I used the labels "next" and "done" and all my issues disappeared! At the beginning I had used numbers for jumping (please look at into the comments strings the numbers which were supposed to be working but that didn't work instead!).

Does anybody know the reason why those numbers used for jumping are wrong?

In normal conditions, I swear I have no problems to count until 20, but it seems that this is not the case :)


Solution

  • You should not use offsets to jump over macros because you don't know how many instructions they contain (and could change between NSIS versions).

    In your case, StrLoc and If/Else/EndIf are macros.

    Labels have zero overhead in the generated installer and should be used (and/or If/EndIf) in most places. Direct offsets are useful in macros that might be included multiple times in the same function/section where you can't use If/EndIf/While (rare) but it quickly gets out of hand. You can use something like !define MyLabel L${__COUNTER__} to create a label for macros like that:

    !macro Test
    !define MyLabel L${__COUNTER__}
    ...
    StrCmp $1 $2 ${MyLabel}_end
    ...
    ${MyLabel}_end:
    !undef MyLabel
    !macroend