Archive: How to declare new variables at runtime


How to declare new variables at runtime
I am calling a system function which returns an array of n data entries in an array + the total number of entries in the array. The total number of entries may vary between computers so I can't define n number of variables at compilation time. I am looking for a method to declare n variables within a function or section, something like this:

...
Function blah
Pop $R0 ; a pointer to the buffer containing the array
Pop $R1 ; the total number of entries in $R1
StrCpy $Counter 1
loop1:
${If} $Counter <> $R1
Var /GLOBAL "Entry_$Counter"
StrCpy $Counter $Counter +1
Goto loop1
${Else}
Goto loop1end
${EndIf}
loop1end:

StrCpy $Counter 1
StrCpy $ArrayElements "w .$Entry_$Counter"
loop2:
${If} $Counter <> $R1
StrCpy $ArrayElements "$ArrayElements, w .$Entry_$Counter"
StrCpy $Counter $Counter +1
Goto loop2
${Else}
Goto loop2end
${EndIf}
loop2end:

System::Call '*$R0("$ArrayElements")' ; get the elements of the array to $Entry_$Counter variables
...
FunctionEnd

The above is not working ofcourse, so I was hoping that somebod ywould have a better idea
Thanks
CF

May be this link will be usefull http://nsis.sourceforge.net/Array_plug-in ;)


Thanks Takhir,
I tried before with AfrowUK's plugin but could not get it to work. My problem, as I stated in my post, is that I do not know the length of the array in advance...
Suppose I start feeding data to an array, until my counter reaches $R1 (total number of entries). Then I would have to pop the data out eventually to variables in order to use them in my system call. Still no good because I would have to define those variables, but I do not know their number in advance ...

It may be obvious how to deal with this but I really can't see the solution

:igor:

CF

[Edit]
I guess if I didn't need all the entries out, I could just pick one at a time, process it and then pick the next until I run out of entries ... Good enough for me :)
However what happens if I want them all?


Use the stack:

Push,
Pop
etc

-Stu


Fair enough.
The build in variables (registers) in NSIS are $0-$9 and $R0-$R9.
Is there a way to have more than 20 variables at the same time, without declaring them when compiling?
CF

[Edit]
Maybe I should explain the problem a bit more...
I have an array of n-elements stored at a memory buffer ($R0 for my example). The only way I can pop the elements out is by calling:

System::Call '*$R0(w .$0, w .$1, ...,w .$n)'
The total number of elements (n) is unknown when I am compiling my program so I cannot define n variables.

How is it possible, using the Array plugin, to pop all the elements out of the memory into an Array of variables (or just into an array)?

For example, if I call
System::Call '*$R0(w .$0)'
I will pop only the first element from the buffer, if I call
System::Call '*$R0(w .$0, w $1)'
I will pop the first and the second etc.
If I have more then 20 elements, I will run out of registers ...

In other words I cannot pop out one at a time from the buffer, I have to pop them out all at once using n variables to accept them ...

CF

Duh, the answer was simple ...
Pop out 20 fisrt then repeat with the remaining setting the first 20 to null :)
CF


This is frustrating ...
If I try to pop 20 elements at a time, I still do not know how to deal with the memory buffer as the system::call command is a function of the number of elements. For example if I pop 5 at a time (so that I don't have to write 20 here!)

; $R0 is the buffer of the momory structure
; $R1 is the number of elements in $R0
NSISArray::New /NOUNLOAD SomeArray
System::Call '*$R0(w $5, w $6, w $7, w $8, w $9)' ; first call
NSISArray::WriteList /NOUNLOAD SomeArray "$5" "$6" "$7" "$8" "$9" /END
NSISArray::SizeOf /NOUNLOAD SomeArray
Pop $R9
StrCmp $R9 $R1 end step2

step2:
System::Call '*$R0(v,v,v,v,v,w $5, w $6, w $7, w $8, w $9)'
NSISArray::WriteList /NOUNLOAD SomeArray "$5" "$6" "$7" "$8" "$9" /END
NSISArray::SizeOf /NOUNLOAD SomeArray
Pop $R9
StrCmp $R9 $R1 end step3

step3:
System::Call '*$R0(v,v,v,v,v,v,v,v,v,v,w $5, w $6, w $7, w $8, w $9)'
NSISArray::WriteList /NOUNLOAD SomeArray "$5" "$6" "$7" "$8" "$9" /END
NSISArray::SizeOf /NOUNLOAD SomeArray
Pop $R9
StrCmp $R9 $R1 end step4
...

end:
...
(plus some code in between to empty the variables before calling calling the structure to ensure that I am not getting the same elements when I reach the end of the structure)
Any ideas on how to improve this?

CF

In the line "System::Call '*$R0(...'" -> the variable $R0 means the memory location of the data in that case. Thus you could use IntOp to go to the next array item by adding the string length (using IntOp). You would also need to know the array size to loop, but I think you already have that.


Thanks deguix, but it it din't work :(

; $R0 is the buffer of the momory structure
; $R1 is the number of elements in $R0
System::Call '*$R0(w .r1)' ; get first entry out
StrLen $2 '$1'
IntOp $2 $2 + 1
IntOp $R0 $R0 + $2
System::Call '*$R0(w.r1)' ; get second entry out
It breaks after the first entry is out.

I can get all the entries out like this:
System::Call '*$R0(w.r1,w.r2,w.r3,....w.rn)
but not one at the time ...
CF

Got it!

; $R0 is the buffer of the momory structure
; $R1 is the number of elements in $R0
System::Call '*$R0(w .r1)' ; get first entry out
StrLen $2 '$1'
IntOp $2 $2 + 2
IntOp $R0 $R0 + $2
System::Call '*$R0(w.r1)' ; get second entry out

If I add two nulls on any entry then call the function again I get the next entry :)

Thanks a lot deguix, you made my day :)

CF

I'd like to add dynamic arrays in my plugin, just need to find time.

-Stu


Looking forward to that
:D
CF


You are just adding 1 null actually, because you are going to the first character of the next string, thus you needed to advance 2 characters. StrLen doesn't count the last null character.


Thanks for the clarification deguix, it makes sense now.
I was trying to enumerate the local groups using NetLocalGroupEnum. Although the previous example seemed to work, it is still wrong in my case.
Here is the one that worked:

!define LOCAL_GROUP_INFO_0 0
System::Int64Op 1 * 0x000000
Pop $R4
System::Call 'netapi32.dll::NetLocalGroupEnum(n,i${LOCAL_GROUP_INFO_0},*i.R1,i${NSIS_MAX_STRLEN},*i.R2,*i.R3,*i.R4)'
NSISArray::New /NOUNLOAD LocalGroups
StrCpy $Counter 0
FeedArray:
${If} $Counter < $R3
System::Call '*$R1(w.R5)'
NSISArray::Write /NOUNLOAD LocalGroups $Counter "$R5"
IntOp $R1 $R1 + 4
IntOp $Counter $Counter + 1
Goto FeedArray
${EndIf}
NSISArray::SizeOf /NOUNLOAD LocalGroups
Pop $0
System::Call 'netapi32.dll::NetApiBufferFree($R1)'
The above code will get all the local group names to the LocalGroups array.
;)

CF