NSIS: problema com $ 0- $ 9, $ R0- $ R9

Saudações a todos que lêem :) O

hub de destino não corresponde ao conteúdo do artigo, mas o que fazer ... - não há temas temáticos para esse fim, mas o mais adequado é "C", porque os leitores mais facilmente serão capazes de perceber o que está escrito.

Objetivo do artigo


Uma opção para resolver o problema de controlar variáveis ​​globais ao gravar o instalador / desinstalador usando o NSIS .

Pequena introdução


Ao escrever o código nsis, o programador tem a oportunidade de usar variáveis ​​globais cujo escopo é o projeto inteiro. Existem apenas 20 deles: $ 0- $ 9 e $ R0- $ R9.
É muito conveniente usá-los, porque isso elimina a necessidade de introduzir variáveis ​​adicionais formalmente destinadas a solucionar problemas-alvo. Eu digo formalmente porque quaisquer variáveis ​​nsis têm um escopo global e, se diferirem em algo, somente com o qualificador const (falando em termos de C / C ++):

!define variable1 ''value 1''

Recursos:

  • variável estática de escopo global;
  • Inicializado mediante declaração;
  • Método de contato: $ {variable1}

Var variable2

Recursos:

  • Variável dinâmica de escopo global;
  • É declarado em qualquer lugar pelo código, mas acima da primeira chamada;
  • É inicializado quantas vezes for necessário, mas apenas dentro de blocos de função e macros;
  • Método de acesso: $ variable2

Assim, dadas as características acima, fica claro que é difícil justificar a criação direcionada de outras variáveis ​​além da estática, porque Como as variáveis ​​globais já existem por padrão, existem o suficiente para satisfazer quaisquer necessidades (e, se não, você precisa fazer as perguntas "apropriadas" ao programador) e outras provavelmente irão apenas entupir o código.

Descrição do problema


Mas o problema é que esse código sempre gera erros:


Function F1
    StrCpy $0 "vladimir"
FunctionEnd

Function F2
    StrCpy $0 "alexei"
    Call F1
    ${If} $0 == "alexei" ; //  $0  "vladimir"
        ; // -  ...
    ${EndIf}
FunctionEnd

E você pode criar muitos exemplos disso, e os especialistas em programação da nsis resolveram esse problema da melhor maneira possível:

  • Alguém apenas observou cuidadosamente todas as variáveis ​​(essas pessoas precisam erguer um monumento);
  • Alguém, principalmente os criadores de vários plug-ins, cada vez que desejavam usar qualquer uma das variáveis ​​apresentadas, o colocava na pilha e, após o final do uso, eles retornavam o valor principal chamando Pop;
  • E alguém produziu variáveis ​​através do Var, conforme descrito acima.

De qualquer forma, todos enfrentaram o problema da falta de um mecanismo universal que resolva o problema de monitorar o estado das variáveis ​​globais.

Aqui me permito oferecer a ela (problemas) uma solução universal.

Solução para o problema


Para iniciantes, um link para o NSISList é um plug-in que introduz a capacidade de usar uma estrutura de dados do tipo lista, que deve ser tomada da mesma maneira que o std :: list no C ++ é percebido.

O segundo passo é o código fonte do mecanismo de solução de problemas :


!verbose 3
!include NSISList.nsh	;      *

/*
  Dump, :

!define F1 "!insertmacro _F1"
!macro _F1 [paramIn1 paramIn2 ... paramInN] [paramOut1 paramOut1 ... paramOutM]
    ${Dump}
    [Push ${paramIn1}
	Push ${paramIn2}
	...
	Push ${paramInN}]
    !ifdef __UNINSTALL__
        Call un.F1
    !else
        Call F1
    !endif
    ${Undump}
    [Pop ${paramOut1}
	Pop ${paramOut2}
	...
	Pop ${paramOutM}]
!macroend

!macro Func_F1 un
    Function ${un}F1
        ;  ...
        ;         $0-$9, $R0-$R9.
        ;        .
    FunctionEnd
!macroend
!insertmacro Func_F1 ""
!insertmacro Func_F1 "un."

*/

/**   Dump */
!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."


/**     nsis-  Dump */
!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."


/**     nsis-  Dump */
!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."

E o terceiro passo é uma pequena descrição de como funciona:

cada função criada e projetada de acordo com a regra descrita pelo comentário anterior do código principal será absolutamente protegida do ponto de vista do perigo de sobrescrever as variáveis ​​globais $ 0- $ 9, $ R0- $ R9 dentro de si e, portanto, - de violação da lógica da função de chamada.

Funciona assim:

  1. A função F1 em si não é chamada diretamente,
    Call F1
    e através do wrapper de macro
    ${F1} [paramIn1 [paramIn2]...[paramInN]] [paramOut1 [paramOut2]...[paramOutM]]
  2. Mesmo antes de a função ser chamada diretamente, ela será chamada
    ${Dump}
    como resultado, os valores atuais das variáveis ​​$ 0- $ 9, $ R0- $ R9 são salvos no Dump. Sob o capô, ele tem muitas listas, cada uma ligada à sua variável alvo;
  3. Carregando na pilha todas as variáveis ​​de destino para a função
    Push ${paramIn1} Push ${paramIn2} ... Push ${paramInN}
    (se for necessário);
  4. A função será chamada;
  5. A função executará sua lógica e sairá;
  6. A chamada acontecerá
    ${Undump}
    como resultado, os valores das variáveis ​​globais armazenadas na última chamada de $ {Dump} serão restaurados;
  7. Descarregar os resultados da função da pilha
    Pop ${paramOut1} Pop ${paramOut2} ... Pop ${paramOutM}
    (se for necessário);
  8. O wrapper de macro na função F1 concluirá seu trabalho.

Conclusão


Como resultado, obtivemos um design universal para escrever com segurança o código nsis.

Você pode até dizer que ele não traz nenhum sinal de menos, exceto que o código compilado funcionará por cerca de 30 ms. Mais devagar.

Espero que isso facilite a vida de alguém :)

Obrigado!

Source: https://habr.com/ru/post/undefined/


All Articles