Pular para o conteúdo principal

Postagem em destaque

🚀 Oferecendo Serviços Remotos de Desenvolvedor AdvPL e Mais 🖥️

🚀 Oferecendo Serviços Remotos de Desenvolvedor AdvPL e Mais 🖥️ Olá pessoal, Espero que este post encontre todos vocês bem! É com grande entusiasmo que compartilho que estou expandindo meus serviços como Desenvolvedor AdvPL para novos desafios e colaborações. Com mais de duas décadas de experiência sólida, minha jornada profissional tem sido enriquecedora, com a oportunidade de participar de projetos empolgantes ao longo dos anos. Agora, estou ansioso para trazer minha experiência e habilidades para novas equipes e projetos, trabalhando de forma remota. Minha expertise abrange não apenas AdvPL, mas também outras tecnologias-chave, incluindo JS, SQL, Infraestrutura e Otimização de Processos. Acredito que essa combinação de conhecimentos me permite oferecer soluções abrangentes e eficazes para uma variedade de necessidades de desenvolvimento. Acredito que a tecnologia tem o poder de transformar negócios e impulsionar o sucesso, e estou comprometido em ajudar meus clientes a alcançar seu

Protheus :: Recuperando Variáveis da Pilha de Chamadas Versão II

Uma versão mais completa das funções de pesquisa e recuperação de variáveis baseada na "Pilha de Chamadas" obtidas à partir do "Tratamento de Erros".
 
#INCLUDE "PROTHEUS.CH"
#INCLUDE "TRYEXCEPTION.CH"
 
#DEFINE STACK_INDEX_PARAMETER    1
#DEFINE STACK_INDEX_SCOPE        2
#DEFINE STACK_INDEX_TYPE         3
#DEFINE STACK_INDEX_VALUE        4
 
#DEFINE STACK_INDEX_ELEMENTS     4 
 
/*/
    Funcao  : ReadStackParameters
    Autor   : Marinaldo de Jesus
    Data    : 19/01/2011
    Uso     : Retornar informações de Variáveis da Pilha de Chamadas
    Sintaxe : StaticCall(U_STACKPUSH,ReadStackParameters,cStack,cParameter,cScope,cModule,aStackParameters)
/*/
Static Function ReadStackParameters(cStack,cParameter,cScope,cModule,aStackParameters)
 
    Local bAscan
 
    Local lScope
    Local lModule
 
    Local nStack
    Local nParameter
    
    Local uValue
 
    BEGIN SEQUENCE
 
        DEFAULT aStackParameters := GetStackParameters()
        
        IF Empty( aStackParameters )
            BREAK
        EndIF
        
        lModule    := !Empty( cModule )
 
        IF ( lModule )
            bAscan := { |x| ( x[ 1 ] == cStack ) .and. ( cModule $ x[ 2 ] ) }
        Else
            bAscan := { |x| ( x[ 1 ] == cStack ) }
        EndIF    
        
        nStack     := aScan( aStackParameters , bAscan )
        IF ( nStack == 0 )
            BREAK
        EndIF
 
        lScope     := !Empty( cScope )
 
        IF ( lScope )
            bAscan :=     { |x| ( x[ STACK_INDEX_PARAMETER ] == cParameter ) .and. ( x[ STACK_INDEX_SCOPE ] == cScope ) }
        Else
            bAscan :=     { |x| ( x[ STACK_INDEX_PARAMETER ] == cParameter ) }
        EndIF
 
        nParameter := aScan( aStackParameters[ nStack ][ 3 ] , bAscan )
        IF ( nParameter == 0 )
            BREAK
        EndIF
 
        uValue     := aStackParameters[ nStack ][ 3 ][ nParameter ][ STACK_INDEX_VALUE ]
 
    END SEQUENCE
 
Return( uValue )
 
/*/
    Funcao  : GetStackParameters
    Autor   : Marinaldo de Jesus
    Data    : 19/01/2011
    Uso     : Obtem Array com a Pilha de Chamadas que sera usado pela ReadStackParameters
    Sintaxe : StaticCall(U_STACKPUSH,GetStackParameters)
/*/
Static Function GetStackParameters()
 
    Local aStackEnv
    Local aStackParameters    := {}
    
    Local cStack
    Local cModule
    Local cStackEnv
    
    Local lIscBlock
    
    Local nStack
    Local nIndexEnv
    Local nStackEnv
 
    Local oException
    
    TRYEXCEPTION
 
        UserException( "IGetStackParameters" )
 
    CATCHEXCEPTION USING oException
 
        cStackEnv    := oException:ErrorEnv
        IF !(;
                ( Chr( 10 ) $ cStackEnv );
                .and.;
                ( Chr( 13 ) $ cStackEnv );
            )    
            cStackEnv    := StrTran( cStackEnv , "  " , CRLF )
            cStackEnv    := StrTran( cStackEnv , "STACK " , CRLF + "STACK " )
        EndIF
        aStackEnv    := StrTokArr( cStackEnv , CRLF )
 
        cStackEnv    := NIL
 
        nIndexEnv    := 0
        nStackEnv    := Len( aStackEnv )
 
        While ( ( ++nIndexEnv ) <= nStackEnv )
 
            IF ( "Public" $ aStackEnv[ nIndexEnv ] )
 
                IF ( "Publicas" $ aStackEnv[ nIndexEnv ] )
                    Loop
                EndIF
 
                nStack := aScan( aStackParameters , { |x| ( x[1] == "PUBLIC" ) } ) 
            
                IF ( nStack == 0 )
                    aAdd( aStackParameters , { "PUBLIC" , "" , Array(0) } )
                    nStack := Len( aStackParameters )
                EndIF
 
                cStackEnv    := aStackEnv[ nIndexEnv ] 
                AddStackParameters( @aStackParameters , @nStack ,  @cStackEnv  )
 
            ElseIF ( "STACK" == SubStr( aStackEnv[ nIndexEnv ] , 1 , 5 ) )
                
                cStackEnv  := AllTrim( StrTran( aStackEnv[ nIndexEnv ] , "STACK" , "" ) )
                lIscBlock  := ( ( "{" $ cStackEnv ) .and. ( "}" $ cStackEnv ) .and. ( "|"  $ cStackEnv ) )
                IF ( lIscBlock )
                    cStack := SubStr( cStackEnv , AT( "{" , cStackEnv ) , RAT( "}" , cStackEnv ) )
                Else
                    cStack := SubStr( cStackEnv , 1 , AT( "(" , cStackEnv ) - 1 )
                EndIF    
                cModule    := StrTran( cStackEnv , cStack , "" )
 
                nStack     := aScan( aStackParameters , { |x| ( x[1] == cStack ) } ) 
 
                IF ( nStack == 0 )
                    aAdd( aStackParameters , { cStack , cModule , Array(0) } )
                    nStack := Len( aStackParameters )
                EndIF
 
                While (;
                            ( ( ++nIndexEnv ) <= nStackEnv );
                            .and.;
                            !( "STACK" == SubStr( aStackEnv[ nIndexEnv ] , 1 , 5 ) );
                            .and.;
                            !( "FILES" == Upper( SubStr( aStackEnv[ nIndexEnv ] , 1 , 5 ) ) );
                        ) 
 
                    cStackEnv    := aStackEnv[ nIndexEnv ] 
                    AddStackParameters( @aStackParameters , @nStack ,  @cStackEnv  )
 
                End While
 
                --nIndexEnv
 
            ElseIF ( "FILES" == Upper( SubStr( aStackEnv[ nIndexEnv ] , 1 , 5 ) ) )
            
                Exit
 
            EndIF
                
        End While
 
    ENDEXCEPTION
 
Return( aStackParameters )
 
/*/
    Funcao  : AddStackParameters
    Autor   : Marinaldo de Jesus
    Data    : 19/01/2011
    Uso     : Carregar os Valores da Pilha de Chamadas
    Sintaxe : AddStackParameters( aStackParameters , nStack ,  cStackEnv  )
/*/
Static Function AddStackParameters( aStackParameters , nStack ,  cStackEnv  )
 
    Local aTokens        := StrTokArr( cStackEnv , ":" )
    Local aDateFormat
    
    Local cType
    Local cScope
    Local cParameter
    Local cDateFormat    := Set( 4 )
 
    Local dDate
 
    Local nToken
    Local nTokens        := Len( aTokens )
    Local nParameter
    Local nDateFormat
 
    Local uValue
    
    IF ( nTokens >= 1 )
        cScope    := Upper( AllTrim( StrTokArr( aTokens[ 1 ] , " " )[1] ) )
    Else
        cScope    := "UNDEFINED"
    EndIF    
 
    IF ( nTokens >= 2 )
        cStackEnv    := aTokens[ 2 ]
           cParameter    := AllTrim( SubStr( cStackEnv , 1 , AT( "(" , cStackEnv ) - 1 ) )
           cType        := SubStr( cStackEnv , AT( "(" , cStackEnv ) + 1 , 1 )
       Else
           cParameter    := "NULL"
           cType        := "U"
       EndIF    
 
    IF ( nTokens >= 3 )
        uValue        := aTokens[ 3 ]
        IF ( nTokens > 3 )
            nToken := 3
            While ( ( ++nToken ) <= nTokens )
                uValue += aTokens[ nToken ]
            End While
        EndIF
    Else
        uValue        := NIL
    EndIF    
 
    TRYEXCEPTION
 
        IF ( cScope $ "PUBLIC/PRIVATE" )
 
            uValue := &( cParameter )
 
        Else
 
            Do Case
                Case ( cType == "C"  )
                    //...
                Case ( cType == "N"  )
                    uValue := Val( uValue )
                Case ( cType == "D"  )
                    dDate := Ctod( uValue )
                    IF Empty( dDate )
                        aDateFormat    := { "yyyy/mm/dd" , "yyyy-mm-dd" , "mm/dd/yyyy" , "mm-dd-yyyy" , "dd/mm/yyyy" , "dd-mm-yyyy" }
                        For nDateFormat := 1 To Len( aDateFormat )
                            Set( 4 , aDateFormat[ nDateFormat ] )
                            dDate := Ctod( uValue )
                            IF !Empty( dDate )
                                Exit
                            EndIF
                        Next nDateFormat
                    EndIF    
                    uValue    := dDate
                Case ( cType == "L"  )
                    uValue := &( uValue )
                Case ( cType == "B"  )
                    uValue := &( uValue )
                Case ( cType == "A"  )
                    uValue := {}
                Case ( cType $ "U/O" )
                    uValue := NIL
            OtherWise
                uValue := NIL    
            End Case 
 
        EndIF
            
    CATCHEXCEPTION
 
        Do Case
            Case ( cType == "C"  )
                uValue := ""
            Case ( cType == "N"  )
                uValue := 0
            Case ( cType == "D"  )
                dDate := Ctod( "" )
            Case ( cType == "L"  )
                uValue := .F.
            Case ( cType == "B"  )
                uValue := { || .F. }
            Case ( cType == "A"  )
                uValue := {}
            Case ( cType $ "U/O" )
                uValue := NIL
        OtherWise
            uValue := NIL    
        End Case     
 
    ENDEXCEPTION                    
 
    aAdd( aStackParameters[ nStack ][3] , Array( STACK_INDEX_ELEMENTS ) )
 
    nParameter := Len( aStackParameters[ nStack ][3] )
 
    aStackParameters[ nStack ][3][ nParameter ][ STACK_INDEX_PARAMETER ] := cParameter
    aStackParameters[ nStack ][3][ nParameter ][ STACK_INDEX_SCOPE     ] := cScope
    aStackParameters[ nStack ][3][ nParameter ][ STACK_INDEX_TYPE      ] := cType
    aStackParameters[ nStack ][3][ nParameter ][ STACK_INDEX_VALUE     ] := uValue
 
    Set( 4 , cDateFormat )
 
Return( NIL )

 

Para obter o código completo e o exemplo de uso clique aqui


Vale salientar que, pra a obtenção das variáveis a serem 'recuperadas', faz-se necessário obtê-las previamente. Isso pode ser feito através da "depuração" do código consultando a  Pilha de Chamadas (Call Stacks) no "Totvs Development Studio", ou simplesmente IDE.



"Todo conhecimento não compartilhado torna-se nulo. Sempre que aprender algo novo compartilhe para que seu conhecimento seja perpetuado"


[]s
иαldσ dj

Comentários

  1. Caro Marinaldo,

    No site do BlackTDN foi publicado um fonte (stackpush.prg) que continha a função ReadStackParameters, que tinha a finalidade de recuperar variáveis das funções da pilha de chamada independente do escopo das mesmas, o que é muito útil para execução de algum ponto de entrada ou rotina customizada. Contudo em determinadas situações, a forma de conseguir isto (disparar uma exceção) provoca interrupções no processamento de rotinas que são executadas via JOB, o que pode ser problema... Com isto em mente, gostaria de saber se há alguma alternativa para este caso em específico para evitar que a exceção disparada a partir da ReadStackParameters interrompa o processamento ou se existe uma forma melhor de acessar as variáveis da mesma maneira.

    Agradeço a atenção,


    Jefferson

    ResponderExcluir
  2. Olá Naldo,
    No uso da stackpush.prg, notei que quando se usa em uma chamada que executa dentro de um JOB/thread, o appserver que faz esta execução começa a alocar memória de forma progressiva até estourar o limite. Existe alguma maneira de desalocar a memória logo após disparar a exceção que faz parte da rotina ?

    ResponderExcluir
    Respostas
    1. Existe um problema conhecido em que determinada versao ao appServer nao desaloca memoria de objetos. Segundo o TDN já existe solução para isso: basta atualizar a Build.

      Excluir
  3. Olá Naldo,
    Ao usar a implementação do stackpush.prg em uma função executada via Job, notei que o appserver que roda a thread aloca memória de forma progressiva até "estourar". Acredito que sejam as chamadas sucessivas da exceção da ReadstackParameters... Existe alguma forma de desalocar a memória e evitar este problema ?

    ResponderExcluir
    Respostas
    1. http://tdn.totvs.com/pages/viewpage.action?pageId=271860860

      TOTVS Technology … 7.00.131227a-20160308 NG
      Correction - Memory Leak (Objects)
      Ir para o final dos metadados
      Criado por Otto Alexandre Monteiro Altorfer em 02 mar, 2017 Ir para o início dos metadados
      Situation
      Correction of memory leak in use of AdvPL objects.
      Occurrence
      In use of ADVPL objects, it was not released from memory after use.
      Correction
      Change in memory cleanup routine.
      Additional Information
      Available in builds after 3/8/2016.
      Revision: 8479

      Excluir

Postar um comentário

Postagens mais visitadas deste blog

BlackTDN :: RLeg ~ Desvendando a Função ParamBox

Para quem precisar desenvolver uma interface de entrada de dados, coisa rápida, e não quer ter aquele trabalhão danado que todos já sabemos, o Protheus tem uma função que ajuda muito, é uma interface semelhante a função Pergunte, porém com muito mais opção de objeto de entrada de dados, alias até colocar o scrollbox desta interface com todos os objetos em outra MsDialog ou Wizard é simples. Vejam o exemplo abaixo, boa sorte! Rleg. //---------------------------------------------------------- // Função exemplo utilizando a função ParamBox() //---------------------------------------------------------- User Function xParamBox() Local aRet := {} Local aParamBox := {} Local aCombo := {"Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"} Local i := 0 Private cCadastro := "xParambox" // ---------------

Protheus :: Chamando Funções do Menu Diretamente e sem a Necessidade de Login

Ferne$ perguntou: "...é possível abrir alguma rotina do sistema sem solicitar login ao usuário, como por exemplo a rotina MATA010..." Sim Ferne$, é possível sim. Abaixo um Exemplo para a Chamada à função MATA010 sem a necessidade de Login no sistema. #INCLUDE "PROTHEUS.CH" #INCLUDE "TBICONN.CH" /*/ Funcao: MATA010Ex Data: 30/04/2011 Autor: Marinaldo de Jesus Descricao: Executar a Funcao MATA010 diretamente sem a necessidade de LOGIN no Protheus Sintaxe: 1 ) U_MATA010Ex ( Chamada diretamente na Tela de Entrada do Sistema ) ; ou 2 ) totvsclient.exe -q -p=u_MATA010Ex -a=01;01 -c=rnp_local -e=rnp -m -l ( Chamada Via Linha de Comando ) /*/ User Function MATA010Ex( cEmpFil ) Local aEmpFil Local bWindowInit := { || __Execute( "MATA010()" , "xxxxxxxxxxxxxxxxxxxx" , "MATA010" , "SIGAFAT" , "SIGAFAT", 1 , .T. ) } Local cEmp Local cFil Local cMod Local cModName := "SIGAFAT" DEFA

BlackTDN :: Customizando a interface de Login no Protheus e by You

A publicação “ BlackTDN :: By You e sua nova tela de login ”  de nosso amigo OBona deu o que falar e, em função disso, esse que a muito não vos escreve resolveu criar uma versão onde será possível personalizar, “por completo”, a tela de login no Protheus/by You. Considerando que OBona já havia “mapeado, identificado e customizado” as imagens peguei-as emprestadas para o exemplo que se segue: O primeiro passo para a customização “total” da interface de login do Protheus/by You será implementar o “Ponto de Entrada” ChgPrDir (Diretório de impressão) . Usaremos esse PE juntamente como programa U_FindMsObject.prg (apresentado pela primeira vez em: Protheus :: ADVPL : The Container : Presents Pandora's box ). Diferente do exemplo proposto por OBona, que substitui, durante o processo de compilação, as imagens padrões do sistema (excluindo-as) por imagens customizadas (com o mesmo nome) este novo exemplo mantém, no RPO, as imagens padrões adicionando novas imagens customizadas que serã