Greetings to all who read :) Thetarget hub does not correspond to the content of the article, but what to do ... - there are no thematic ones for the purpose, but the most suitable one is “C”, because readers of it will most easily be able to perceive what is written.Purpose of the article
An option to solve the problem of controlling global variables when writing the installer / uninstaller using NSIS .Small introduction
When writing nsis code, the programmer has the opportunity to use global variables whose scope is the entire project. There are only 20 of them: $ 0- $ 9 and $ R0- $ R9.It is very convenient to use them, because this eliminates the need to introduce additional variables formally intended for solving target problems. I say, formally, because any nsis variables have a global scope and if they differ in anything, then only with the qualifier const (speaking in C / C ++ terms):!define variable1 ''value 1''
Features:- static variable of global scope;
- Initialized upon declaration;
- Contact Method: $ {variable1}
Var variable2
Features:- Dynamic variable of global scope;
- It is declared anywhere by code, but above the first call;
- It is initialized as many times as necessary, but only inside function blocks and macros;
- Access Method: $ variable2
Thus, given the above features, it becomes clear that the targeted creation of any variables other than static is difficult to justify, because global variables already exist by default, there are enough of them to satisfy any needs (and if not, you need to ask the "appropriate" questions to the programmer) and any other ones will most likely only clog the code.Description of the problem
But the trouble is, this code always generates errors:
Function F1
StrCpy $0 "vladimir"
FunctionEnd
Function F2
StrCpy $0 "alexei"
Call F1
${If} $0 == "alexei" ;
;
${EndIf}
FunctionEnd
And you can come up with a lot of examples of this, and the nsis programming craftsmen solved this problem as best they could:- Someone just carefully watched all the variables (such people need to erect a monument));
- Someone, mainly the creators of various plug-ins, each time wanting to use any of the variables presented, made it Push onto the stack, and after the end of use they returned the primary value by calling Pop;
- And someone produced variables through Var, as described above.
In any case, they all faced the problem of the lack of a universal mechanism that solves the problem of monitoring the state of global variables.Here I allow myself to offer her (problems) a universal solution.Solution to the problem
To begin with, the link to NSISList is a plugin that introduces the ability to use a list-type data structure, which should be taken in a similar way to std :: list in C ++.The second step is the source code of the problem-solving mechanism :
!verbose 3
!include NSISList.nsh ; *
!define InitDump "!insertmacro _InitDump"
!macro _InitDump
!ifdef __UNINSTALL__
Call un.InitDump
!else
Call InitDump
!endif
!macroend
!macro Func_InitDump un
Function ${un}InitDump
# $0-$9
${List.Create} d0
${List.Create} d1
${List.Create} d2
${List.Create} d3
${List.Create} d4
${List.Create} d5
${List.Create} d6
${List.Create} d7
${List.Create} d8
${List.Create} d9
# $R0-$R10
${List.Create} dR0
${List.Create} dR1
${List.Create} dR2
${List.Create} dR3
${List.Create} dR4
${List.Create} dR5
${List.Create} dR6
${List.Create} dR7
${List.Create} dR8
${List.Create} dR9
FunctionEnd
!macroend
!insertmacro Func_InitDump ""
!insertmacro Func_InitDump "un."
!define Dump "!insertmacro _Dump"
!macro _Dump
!ifdef __UNINSTALL__
Call un.Dump
!else
Call Dump
!endif
!macroend
!macro Func_Dump un
Function ${un}Dump
# $0-$9
${List.Add} d0 $0
${List.Add} d1 $1
${List.Add} d2 $2
${List.Add} d3 $3
${List.Add} d4 $4
${List.Add} d5 $5
${List.Add} d6 $6
${List.Add} d7 $7
${List.Add} d8 $8
${List.Add} d9 $9
# R0-R9
${List.Add} dR0 $R0
${List.Add} dR1 $R1
${List.Add} dR2 $R2
${List.Add} dR3 $R3
${List.Add} dR4 $R4
${List.Add} dR5 $R5
${List.Add} dR6 $R6
${List.Add} dR7 $R7
${List.Add} dR8 $R8
${List.Add} dR9 $R9
FunctionEnd
!macroend
!insertmacro Func_Dump ""
!insertmacro Func_Dump "un."
!define Undump "!insertmacro _Undump"
!macro _Undump
!ifdef __UNINSTALL__
Call un.Undump
!else
Call Undump
!endif
!macroend
!macro Func_Undump un
Function ${un}Undump
# $0-$9
${List.Pop} $0 d0
${List.Pop} $1 d1
${List.Pop} $2 d2
${List.Pop} $3 d3
${List.Pop} $4 d4
${List.Pop} $5 d5
${List.Pop} $6 d6
${List.Pop} $7 d7
${List.Pop} $8 d8
${List.Pop} $9 d9
# R0-R9
${List.Pop} $R0 dR0
${List.Pop} $R1 dR1
${List.Pop} $R2 dR2
${List.Pop} $R3 dR3
${List.Pop} $R4 dR4
${List.Pop} $R5 dR5
${List.Pop} $R6 dR6
${List.Pop} $R7 dR7
${List.Pop} $R8 dR8
${List.Pop} $R9 dR9
FunctionEnd
!macroend
!insertmacro Func_Undump ""
!insertmacro Func_Undump "un."
And the third step is a small description of how it works:Each function created and designed according to the rule described by the previous main code comment will be absolutely protected from the point of view of the danger of rewriting the global variables $ 0- $ 9, $ R0- $ R9 inside it, and therefore - from violation of the logic of the calling function.It works like this:- The F1 function itself is not called directly,
Call F1
and through the macro wrapper${F1} [paramIn1 [paramIn2]...[paramInN]] [paramOut1 [paramOut2]...[paramOutM]]
- Even before the function is called directly, it will be called
${Dump}
as a result, the current values of the variables $ 0- $ 9, $ R0- $ R9 are saved in Dump. Under the hood he has a lot of lists, each tied to its target variable; - Loading on the stack all the target variables for the function
Push ${paramIn1} Push ${paramIn2} ... Push ${paramInN}
(if it is needed); - The function will be called;
- The function will execute its logic and exit;
- Call will happen
${Undump}
as a result, the values of global variables stored on the last call of $ {Dump} will be restored; - Unloading the function results from the stack
Pop ${paramOut1} Pop ${paramOut2} ... Pop ${paramOutM}
(if it is needed); - The macro wrapper on the F1 function will complete its work.
Conclusion
As a result, we got a universal design for safe writing of nsis code.You can even say that it does not bring any minuses, except that the compiled code will work for about 30 ms. slower.Hope this makes life easier for someone :)Thank you!