forbjok
21st November 2008 00:34 UTC
Local variables / Passing variables to functions
Hi.
I use NSIS quite a lot for various installers and updaters, and it works excellently for doing common installer tasks such as installing/copying files, making registry changes and creating shortcuts.
Combined with custom NSI script generator software I've written to generate scripts, it's a major improvement over any previous commercial installers I've used.
However, any time the need arises to do more than just simple file operations in the NSI script some lack of basic features in the scripting language become painfully obvious.
I am of course referring to the lack of support for local variables in functions, and the inability to pass variables directly to functions (like "myfunction(var1, "string", 5)").
I'm well aware that nothing is really impossible - most things can be done using the assembly-like stack system, with push/pop/exch.
The problem is that this generally results in very large functions that consist 90% of push/exch/pop statements in order to get any needed arguments and preserve the global variables through the function. (to see what I mean, just take a look in the standard includes that come with NSIS - though I'm sure anyone who has used NSIS for some time will know what I'm talking about immediately)
This extends to such a degree that when more advanced operations need to be done it will often be easier to simply write a full-fledged program in another programming language and have NSIS run the compiled executable during installation.
Basically, I'm wondering if there is any chance support for these things will ever be added to the scripting language.
It would really be a major improvement, and would simplify things greatly when performing more advanced tasks in NSIS.
LoRd_MuldeR
21st November 2008 04:03 UTC
There is a workaround for "nicer" function calls in NSIS:
Combine functions and macros!
I usually do it that way:
Var _Arg1
Var _Arg2
Var _Result
!macro _Call func return param1 param2
Push $_Arg1
Push $_Arg2
StrCpy $_Arg1 '${param1}'
StrCpy $_Arg2 '${param2}'
Call ${func}
StrCpy ${return} $_Result
Pop $_Arg2
Pop $_Arg1
!macroend
Functions are declared like that:
!define MyAdder "!insertmacro _MyAdder"
!macro _MyAdder return param1 param2
!insertmacro _Call MyAdderFunc ${return} '${param1}' '${param2}'
!macroend
Function MyAdderFunc
IntOp $_Result $_Arg1 + $_Arg2
FunctionEnd
; ---------------------------------------------
!define MyAppend "!insertmacro _MyAppend"
!macro _MyAppend return param1 param2
!insertmacro _Call MyAppendFunc ${return} '${param1}' '${param2}'
!macroend
Function MyAppendFunc
StrCpy $_Result '$_Arg1$_Arg2'
FunctionEnd
; ---------------------------------------------
!define MyDouble "!insertmacro _MyDouble"
!macro _MyDouble return param1
!insertmacro _Call MyDoubleFunc ${return} '${param1}' ''
!macroend
Function MyDoubleFunc
${MyAdder} $_Result $_Arg1 $_Arg1
FunctionEnd
; ---------------------------------------------
!define MyQuad "!insertmacro _MyQuad"
!macro _MyQuad return param1
!insertmacro _Call MyQuadFunc ${return} '${param1}' ''
!macroend
Function MyQuadFunc
${MyDouble} $_Result $_Arg1
${MyDouble} $_Result $_Result
FunctionEnd
In your sections you then use it like that:
Section "Some Section"
${MyAdder} $0 21 21
DetailPrint "21 + 21 = $0"
${MyAppend} $0 "Win" "Amp"
DetailPrint '"Win" + "Amp" = "$0"'
${MyDouble} $0 8
DetailPrint "8 x 2 = $0"
${MyQuad} $0 11
DetailPrint "11 x 4 = $0"
SectionEnd
It still requires a bunch of code. But at least the function call logic is separated from the actual function code. And you can move all that stuff to an include file. What matters most: Calling the function is very clean and simple!
kichik
21st November 2008 08:32 UTC
You can also use nfu.Function.
forbjok
21st November 2008 09:24 UTC
Thanks for the replies.
NfUtils does seem like a very convenient workaround, if it does what I think it does. (automate handling of function input parameters and restoration of variables at the end)
I will definitely check that out.
However, I still think that this functionality is fundamental enough that it would be better if supported directly in the scripting language.
So I'm still wondering (and hoping) whether there is any chance of this being included in NSIS eventually. (if not in v2, then possibly in v3 - if there is a v3 planned?) :)