#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 informacoes de Variaveis da Pilha de Chamadas
Sintaxe: StaticCall(U_STACKPUSH,ReadStackParameters,cStack,cParameter,cScope,cModule)
/*/
Static Function ReadStackParameters( cStack , cParameter , cScope , cModule )
Local aStackParameters
Local bAscan
Local lScope
Local lModule
Local nStack
Local nParameter
Local uValue
BEGIN SEQUENCE
aStackParameters := GetStackParameters()
IF Empty( aStackParameters )
BREAK
EndIF
lModule := !Empty( cModule )
IF ( lModule )
nStack := aScan( aStackParameters , { |x| ( x[ 1 ] == cStack ) .and. ( cModule $ x[ 2 ] ) } )
Else
nStack := aScan( aStackParameters , { |x| x[ 1 ] == cStack } )
EndIF
IF ( nStack == 0 )
BREAK
EndIF
lScope := !Empty( cScope )
IF ( lScope )
nParameter := aScan( aStackParameters[ nStack ][ 3 ] , { |x| ( x[ STACK_INDEX_PARAMETER ] == cParameter ) .and. ( x[ STACK_INDEX_SCOPE ] == cScope ) } )
Else
nParameter := aScan( aStackParameters[ nStack ][ 3 ] , { |x| ( x[ STACK_INDEX_PARAMETER ] == cParameter ) } )
EndIF
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 nStack
Local nIndexEnv
Local nStackEnv
Local oException
TRYEXCEPTION
UserException( "IGetStackParameters" )
CATCHEXCEPTION USING oException
cStackEnv := oException:ErrorEnv
cStackEnv := StrTran( cStackEnv , " " , CRLF )
cStackEnv := StrTran( cStackEnv , "STACK " , CRLF + "STACK " )
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" , "" ) )
cStack := SubStr( cStackEnv , 1 , AT( "(" , cStackEnv ) - 1 )
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 )
Static Function AddStackParameters( aStackParameters , nStack , cStackEnv )
Local aToken := StrTokArr( cStackEnv , ":" )
Local cType
Local cScope
Local cParameter
Local nToken := Len( aToken )
Local nParameter
Local uValue
IF ( nToken >= 1 )
cScope := Upper( AllTrim( StrTokArr( aToken[ 1 ] , " " )[1] ) )
Else
cScope := "UNDEFINED"
EndIF
IF ( nToken >= 2 )
cStackEnv := aToken[ 2 ]
cParameter := AllTrim( SubStr( cStackEnv , 1 , AT( "(" , cStackEnv ) - 1 ) )
cType := SubStr( cStackEnv , AT( "(" , cStackEnv ) + 1 , 1 )
Else
cParameter := "NULL"
cType := "U"
EndIF
IF ( nToken >= 3 )
uValue := aToken[ 3 ]
Else
uValue := NIL
EndIF
TRYEXCEPTION
Do Case
Case ( cType == "N" )
uValue := Val( uValue )
Case ( cType == "D" )
uValue := Ctod( uValue )
Case ( cType == "L" )
uValue := &( uValue )
Case ( cType == "B" )
uValue := &( uValue )
Case ( cType == "A" )
uValue := {}
Case ( cType $ "U/O" )
uValue := NIL
End Case
CATCHEXCEPTION
uValue := NIL
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
Return( NIL )
|
Como sempre, o Naldo "mata o problema e mostra o código!". Esta solução (mesmo que temporária) atendeu perfeitamente no meu caso.
ResponderExcluirNaldo,
ResponderExcluirFantastico...
Dificil acreditar que era possível uma solução assim....
Ferne$ deixou um novo comentário sobre a sua postagem "Protheus :: Recuperando Variáveis da Pilha de Cham...":
ResponderExcluirQue show Naldo, a algum tempo atras precisei de algo parecido no template ACD, precisava obter um valor da tela em um ponto de entrada, abri um chamado para Totvs solicitando que a variavel fosse enviada via ParamIXB e minha solucao paleativa foi usar a funcao (VTSave) responsavel por montar um Array com as informacoes da tela.
Muito util sua solucao
Cara,
ResponderExcluirjá fiz cada gambi pra conseguir recuperar valores de escopo LOCAL em um determinado PE.
Sempre pensei em uma forma de recuperar esses valores, apesar de ser um dado volatil, sera que seria possivel obte-lo da memoria.
¬¬
Deve ter uma forma mas eu a desconheço. As variáveis estão lá, na Pilha... só esperando serem encontradas. A unica forma que encontrei de recuperá-las foi através do Tratamento de Erros. Então se deseja obter uma variável de escopo Local do Tipo Numérica, Data, Caractere ou Lógica, poderá abrir mão do código que disponibilizei para "Download". Esse código serve para recuperár os valores de Static, Private e Public também. Para as variáveis de escopo Local e Static não obteremos Arrays, Blocos de Código e Objetos, Limitação essa que não existe para as de escopo Private e Public.
ResponderExcluir[]s
иαldσ dj
Tenho uns amigos malucos de ciência da computação,
ResponderExcluirvou ver com eles esse sistema de endereçamento de memoria, se existe alguma assinatura do protheus que as identifique.
Nem que tenhamos que buscar esses valores descendo ao nível mais baixo e criando uma DLL ou EXE para ser executado externamente ao Protheus.
Vou questiona-los!
Abs
Amonimo!
¬¬
hehehe... Essa eu quero ver
ResponderExcluirNaldo,
ResponderExcluirMuito boa sua solução porém, quando fui compilar ocorreu um erro de sintaxe na linha 30 do rdmake U_StackPush.prg, com a instrução DEFAULT aStackParameters := GetStackParameters().
Não estaria faltando o include do PROTHEUS.CH ?
Garoto experto... Falha minha não ter incluido a chamada ao #include "protheus.ch", vou corrigir no original e disponibilizar para "Download".
ResponderExcluirUma observação. NÃO É RDMAKE. RDMAKE era um "Pseudo Compilador" que convertia o código, escrito em CodBase, de forma que o "SIGA ADVANCED" pudesse interpretá-lo já em advpl, criamos verdadeiras "Functions" que são executadas exatamente igual às "Functions" criadas pela equipe de IP.
[]s
иαldσ dj