Controle de Acesso
Moderador: Moderadores
- Marcos
- Usuário Nível 3

- Mensagens: 355
- Registrado em: 20 Set 2003 09:16
- Localização: Cáceres/Mato Grosso
Controle de Acesso
Estou abrindo este tópico porque após várias pesquisas aqui no fórum não achei nada relacionado, apenas entradas com Senhas, mas me refiro aqui a controles de acesso com permissões a determinadas telas, o que o usuário pode ou não pode fazer dentro do sistema, como usuário de sistema, já vi vários controles de formas diferentes, muitos até ruim de usar, outros sistemas com remendos, ou seja, pensou num controle e o sistema foi criado, depois não foi atendido 100%, assim remendaram o sistema dando permissões por botões, e ficou um saco para o usuário, portanto a minha pergunta a todos, qual a melhor forma de criar um controle de acesso para não se arrepender no futuro ?
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Controle de Acesso
É uma questão complicada essa.
Aqui faço tudo baseado em opções do menu, e cada um tem seu nome.
A configuração de acessos tem a cópia do menu pra escolher entre sim/não, por usuário.
Qualquer dia adiciono opção de grupos, pra configurar acesso de um grupo, e cadastrar usuários em determinados grupos.
Há pouco tempo acrescentei a opção do usuário *.*, que define opções de acesso geral.
A checagem é simples: if TemAcesso("nomeopcao")
Tenho uma opção especial no menu, aonde acrescento opções não visíveis, só pra usar a mesma rotina de configuração.
Por exemplo, se pode confirmar pedido sem saldo em estoque, idem com cliente devendo, etc.
Então na configuração é escolher o usuário, e nas opções do menu escolher entre sim/não.
Nessa mesma configuração dá pra fazer o contrário: a partir de uma opção ver/configurar usuários que podem acessar.
Para o que falei sobre grupo, faltaria eu criar a opção de criar grupos e usuários de cada grupo.
A checagem do grupo substituiria o "*.*" , sendo que "*.*" seria o grupo geral.
A checagem não é o problema, mas sim a configuração ficar fácil pro usuário.
Por eu usar uma cópia no estilo do menu, acaba sendo no estilo que estão acostumados.
Como meu menu é um array, a rotina de configuração apenas usa o array do menu pra permitir configurar.
Tenho lá:
- meu usuário - ele é nível máximo, e não depende de configuração
- usuário administrador - a única diferença é ter acesso ao módulo de configurar usuários, e acaba tendo acesso a algo mais
- usuário comum - só tem acesso ao que liberarem pra ele
- *.* - equivale a "qualquer um". liberou pra este liberou pra todos
E o menu... se o usuário não tiver acesso a determinada opção, ela nem aparece.
Não é dos melhores, mas tá funcionando e não requer nenhuma mudança ao criar novas opções.
Aqui faço tudo baseado em opções do menu, e cada um tem seu nome.
A configuração de acessos tem a cópia do menu pra escolher entre sim/não, por usuário.
Qualquer dia adiciono opção de grupos, pra configurar acesso de um grupo, e cadastrar usuários em determinados grupos.
Há pouco tempo acrescentei a opção do usuário *.*, que define opções de acesso geral.
A checagem é simples: if TemAcesso("nomeopcao")
Código: Selecionar todos
FUNCTION TemAcesso( cNomeOpcao )
LOCAL lTemAcesso := .T.
IF .NOT. Encontra( AppUserName() + cNomeOpcao, "senhas" )
IF .NOT. Encontra( "*.*" + cNomeOpcao, "senhas" )
lValue := .F.
ENDIF
ENDIF
RETURN lTemAcesso
Por exemplo, se pode confirmar pedido sem saldo em estoque, idem com cliente devendo, etc.
Então na configuração é escolher o usuário, e nas opções do menu escolher entre sim/não.
Nessa mesma configuração dá pra fazer o contrário: a partir de uma opção ver/configurar usuários que podem acessar.
Para o que falei sobre grupo, faltaria eu criar a opção de criar grupos e usuários de cada grupo.
A checagem do grupo substituiria o "*.*" , sendo que "*.*" seria o grupo geral.
A checagem não é o problema, mas sim a configuração ficar fácil pro usuário.
Por eu usar uma cópia no estilo do menu, acaba sendo no estilo que estão acostumados.
Como meu menu é um array, a rotina de configuração apenas usa o array do menu pra permitir configurar.
Tenho lá:
- meu usuário - ele é nível máximo, e não depende de configuração
- usuário administrador - a única diferença é ter acesso ao módulo de configurar usuários, e acaba tendo acesso a algo mais
- usuário comum - só tem acesso ao que liberarem pra ele
- *.* - equivale a "qualquer um". liberou pra este liberou pra todos
E o menu... se o usuário não tiver acesso a determinada opção, ela nem aparece.
Não é dos melhores, mas tá funcionando e não requer nenhuma mudança ao criar novas opções.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Controle de Acesso
Marcos, esta é uma questão bem complexa. Apanhei muito ate achar um método menos doloroso.
Quanto a "remendo" alterações sempre podem ocorrer em sistemas que tem constantes atualizações, pois um novo módulo ou opção requer uma nova permissão. Exemplo, o usuário pode ter acesso a listagem de produtos e por necessidade foi criado um novo módulo de inclusão de "observações" abrindo um novo acesso a ser controlado.
Segui a seguinte lógica. Criei um dbf exclusivo com 2 campos, onde o primeiro chama-se LINHA tem +- 80 caracteres, o segundo PERMISSAO com 1 caracter onde constam as descrições dos acessos conforme abaixo:
No cadastro do usuario defini um campo de 500 carateres que é automaticamente preenchido com "N" ao cadastra-lo. Cada posicao neste campo corresponde ao numero
inicial conforme acima, 001, 002 etc. Para saber se o usuario tem ou nao acesso criei uma função que indica qual é a parte do sistema onde o usuario esta e faz a busca na tabela acima.
Por exemplo, ao entrar na tela de vendas,
No meu caso ao entrar no sistema o usuario se loga, entao o sistema ja tem o seu codigo. Na funcao tempermissao() eu faço uma busca na tabela do usuario pelo codigo dele, acho o campo de 500 caracteres e vejo o parametro recebido, no exemplo, "001" então verifico na primeira posicao do campo se esta marcado
com SN.
Outra facilidade que acho é a manutenção e criação de novas opções, posso editar colocando novos textos usando o COPY TO com opção [SDF] para criar uma versao texto das permissoes e após minhas alterações importo o novo conteudo para o dbf usando APPEND FROM com opção [SDF].
Essa é minha dica, não ache que será fácil, mapear todas as telas de um sistema e depois fazer ajustes e manutenção dá muito trabalho.
Boa sorte.
Quanto a "remendo" alterações sempre podem ocorrer em sistemas que tem constantes atualizações, pois um novo módulo ou opção requer uma nova permissão. Exemplo, o usuário pode ter acesso a listagem de produtos e por necessidade foi criado um novo módulo de inclusão de "observações" abrindo um novo acesso a ser controlado.
Segui a seguinte lógica. Criei um dbf exclusivo com 2 campos, onde o primeiro chama-se LINHA tem +- 80 caracteres, o segundo PERMISSAO com 1 caracter onde constam as descrições dos acessos conforme abaixo:
Código: Selecionar todos
#MENU VENDAS
001 - Pode vender......................................................[S]
002 - vender a dinheiro.............................................[S]
003 - vender a cartao...............................................[N]
004 - Cancelar venda..................................................[N]
005 - Acesso a Orcamentos Gravados...............................[S]
006 - registrar orcamento.........................................[S]
007 - apagar orcamento...........................................[N]
....
100 - Excluir dados....................................................[S]
inicial conforme acima, 001, 002 etc. Para saber se o usuario tem ou nao acesso criei uma função que indica qual é a parte do sistema onde o usuario esta e faz a busca na tabela acima.
Por exemplo, ao entrar na tela de vendas,
Código: Selecionar todos
if tempermissao("001")!=.t.
return .f.
endif
com SN.
Código: Selecionar todos
function tempermissao(setor)
** nusuario é o codigo do usuario recebido no login, ela deve ser global/public
LOCAL retorno:=.f.
select ("usuarios")
LOCATE FOR usuario=nusuario
if found()
if substr(campo500,val(setor),1)="S"
retorno:=.t.
endif
endif
return retorno
Essa é minha dica, não ache que será fácil, mapear todas as telas de um sistema e depois fazer ajustes e manutenção dá muito trabalho.
Boa sorte.
Clipper 5.2e / Blinker 5.1 / Harbour 3.2 / GTwvg
- Marcos
- Usuário Nível 3

- Mensagens: 355
- Registrado em: 20 Set 2003 09:16
- Localização: Cáceres/Mato Grosso
Controle de Acesso
Marcos,
No sistema antigo em clipper, tinha algo parecido com a idéia do Andril. Depois que passei para Harbour, estou até hoje para implementar , e não deu certo.
Já vi sistemas que colocam nivel 1 ,nivel 2 de acessos , talvez fique + facil , mas nem faria assim acho que não resolve.
Pretendo fazer da seguinte maneira.
Primeiro:
Todos os cadastros tem que ter permissão de Inclusão, Alteração,Exclusão e Consulta ( se não pode consultar, o resto já tá definido que não pode.
Em relatórios também definir se pode imprimir ou só visualizar. Um vez em uma empresa o funcionário foi mandado embora, mas antes imprimiu todos os clientes para levar no concorrente. Determinados funcionários por exemplo não pode acessar relatórios financeiros.
Segundo:
criar um arquivo de direitos e definir tudo o que pode e o que não pode para cada tipo.
por exemplo:
Gerente de contas a receber
Auxiliar de Contas a receber.
Auxiliar de vendas
etc.
Terceiro:
criar um arquivo das senhas/usuários.
ao cadastrar o usuário, definir qual tabela de direitos utilizar.
Não definir as permissões para cada usuário, daria muito trabalho.
Poka.
No sistema antigo em clipper, tinha algo parecido com a idéia do Andril. Depois que passei para Harbour, estou até hoje para implementar , e não deu certo.
Já vi sistemas que colocam nivel 1 ,nivel 2 de acessos , talvez fique + facil , mas nem faria assim acho que não resolve.
Pretendo fazer da seguinte maneira.
Primeiro:
Todos os cadastros tem que ter permissão de Inclusão, Alteração,Exclusão e Consulta ( se não pode consultar, o resto já tá definido que não pode.
Em relatórios também definir se pode imprimir ou só visualizar. Um vez em uma empresa o funcionário foi mandado embora, mas antes imprimiu todos os clientes para levar no concorrente. Determinados funcionários por exemplo não pode acessar relatórios financeiros.
Segundo:
criar um arquivo de direitos e definir tudo o que pode e o que não pode para cada tipo.
por exemplo:
Gerente de contas a receber
Auxiliar de Contas a receber.
Auxiliar de vendas
etc.
Terceiro:
criar um arquivo das senhas/usuários.
ao cadastrar o usuário, definir qual tabela de direitos utilizar.
Não definir as permissões para cada usuário, daria muito trabalho.
Poka.
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Controle de Acesso
Eu deixo por conta do usuário administrativo.
No caso de um novo vendedor, basta cadastrar o novo vendedor, e "importar" os acessos de outro vendedor qualquer.
Só pra ilustrar, a minha rotina de configuração de senhas.
Como eu disse, não é das melhores, mas tem atendido.
É tudo na base do Sim ou Não, podendo liberar opção, ou opção + submenus.
No último nível, se der um ENTER a mais, aparece essa opção de adicionar/remover usuários à opção atual.
E tudo retirado automaticamente do menu em array.
o menu principal é montado assim:
e o menu interno, dos pedidos por exemplo, assim:
e algumas opções extras, assim:
No caso destas configurações extras, elas fazer parte do menu, mas não aparecem no menu do usuário.
Foi a forma de encontrei pra configuração de senhas continuar a mesma automática.
A única diferença entre o menu e a configuração de senhas é que o primeiro menu também fica na vertical na configuração.
No caso de um novo vendedor, basta cadastrar o novo vendedor, e "importar" os acessos de outro vendedor qualquer.
Só pra ilustrar, a minha rotina de configuração de senhas.
Como eu disse, não é das melhores, mas tem atendido.
É tudo na base do Sim ou Não, podendo liberar opção, ou opção + submenus.
No último nível, se der um ENTER a mais, aparece essa opção de adicionar/remover usuários à opção atual.
E tudo retirado automaticamente do menu em array.
o menu principal é montado assim:
Código: Selecionar todos
MenuOption( "Movto" )
MenuDrop()
MenuOption( "Pedidos/Notas Fiscais" )
MenuDrop()
MenuOption( "Orçamentos/Pedidos", "P0600PED" )
MenuOption( "Emissor JPA", "PEMISSOR" )
MenuOption( "Nota Fiscal (Serviços)", "PNOT0010" )
MenuOption( "Consulta a Notas Fiscais", "PNOT0020" )
Código: Selecionar todos
IF TemAcesso( "ADMPEDNOT" )
AAdd( oFrm:acMoreOptions, "<N>NFCupom" )
AAdd( oFrm:acMoreOptions, "<W>VerPDF" )
ENDIF
IF TemAcesso( "ADMPEDCTE" )
AAdd( oFrm:acMoreOptions, "<T>CTE" )
ENDIF
IF TemAcesso( "ADMPEDGAR" )
AAdd( oFrm:acMoreOptions, "<B>CodBarras" )
ENDIF
Código: Selecionar todos
IF jpclista->csBloqueio $ "01"
IF TemAcesso( "ADMPEDBLO" )
IF .NOT. MsgYesNo( "Cliente com Status " + Trim( jpclista->csDescri ) + " não autorizada a confirmação" + HB_EOL() + ;
"Usuário atual consegue autorizar. Continua?" )
RETURN .F.
ENDIF
GravaOcorrencia( "JPPEDI", jppedi->pdPedido, "Autorizado pra cliente com status " + Trim( jpclista->csDescri ) )
ELSE
MsgStop( "Cliente com Status " + Trim( jpclista->csDescri ) + " não autorizada a confirmação" )
RETURN .F.
ENDIF
ELSEIF jpclista->csBloqueio == "2"
MsgWarning( "Cliente com Status " + Trim( jpclista->csDescri ) )
ENDIF
Foi a forma de encontrei pra configuração de senhas continuar a mesma automática.
A única diferença entre o menu e a configuração de senhas é que o primeiro menu também fica na vertical na configuração.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- Marcos
- Usuário Nível 3

- Mensagens: 355
- Registrado em: 20 Set 2003 09:16
- Localização: Cáceres/Mato Grosso
Controle de Acesso
As ideias são bem interessante, muito enriquecedoras, penso em fazer por telas, ou seja, permitir ou não a tela que o usuário terá acesso, mas daí vem a questão, e se determinado usuário pode Incluir um Cliente e não excluir?! Neste caso as permissões deveriam ser por botões, aumentando o stress do usuário ao dar as permissões.
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Controle de Acesso
Tem caso onde crio a opção duas vezes, por exemplo, clientes é PCADASTRO, então crio PCADASTROB pra versão limitada.
No meu caso, o nome do fonte já sai do menu.
Em fonte, acrescento essas opções no menu, que ficam invisíveis ao usuário, e a configuração já resolve.
Como recurso extra, criei uma opção pra digitar usuário,senha e um código de liberação.
Caso tenha esquecido de liberar alguma coisa, isso já libera pro usuário.
Facilita na hora de resolver, ou pra novos módulos.
O negócio é começar a fazer. Conforme for usando, vai vendo o que vai precisando.
Não precisa querer resolver tudo logo na primeira rotina, pode se complicar e acabar não resolvendo nada.
Em outros casos, crio CLIENTEINC, CLIENTALT, CLIENTEXC, e configuro pra essas opções, usando internamente igual mostrei no exemplo de pedidos.
Em um cliente a necessidade foi a primeira opção, já em outro foi a segunda.
A gente vai ajustando conforme vai acontecendo.
No meu caso, o nome do fonte já sai do menu.
Em fonte, acrescento essas opções no menu, que ficam invisíveis ao usuário, e a configuração já resolve.
Código: Selecionar todos
PROCEDURE MenuPrincipal
...
IF Click()
m_Prog := NomeQueTemNoMenu
SAVE SCREEN TO xTela
CLS
@ 0, 0 SAY Padc( "TextoQueTemNoMenu", MaxCol() )
@ 1, 0 SAY Replicate( Chr(196), MaxCol() )
DO( m_Prog )
RESTORE SCREEN FROM xTela
ENDIF
RETURN
PROCEDURE PCADASTRO
IF m_Prog == "PCADASTRO"
oFrm:acOpcoes := "IAEC" // inclui/altera/exclui/consulta
ELSE
oFrm:acOptions := "C" // só consulta
ENDIF
...
PROCEDURE PCADASTROB
DO PCADASTRO
RETURN
Caso tenha esquecido de liberar alguma coisa, isso já libera pro usuário.
Facilita na hora de resolver, ou pra novos módulos.
O negócio é começar a fazer. Conforme for usando, vai vendo o que vai precisando.
Não precisa querer resolver tudo logo na primeira rotina, pode se complicar e acabar não resolvendo nada.
Em outros casos, crio CLIENTEINC, CLIENTALT, CLIENTEXC, e configuro pra essas opções, usando internamente igual mostrei no exemplo de pedidos.
Em um cliente a necessidade foi a primeira opção, já em outro foi a segunda.
A gente vai ajustando conforme vai acontecendo.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Controle de Acesso
Minha rotina de configuração, note que é tudo manual, nem prompt eu uso, e trata também mouse, por isso tá grande (rs...).
É a vantagem de usar um array do menu, e aproveitar na configuração.
No final, só salvar nas senhas o resultado do array.
É a vantagem de usar um array do menu, e aproveitar na configuração.
No final, só salvar nas senhas o resultado do array.
Código: Selecionar todos
FUNCTION BoxAcesso( mLini, mColi, mMenuOpt, mOpc, mTitulo, mSaiSetas )
LOCAL mCont, mLinf, mColf, mTecla, mReturn
mLinf := mLini + Len( mMenuOpt ) + 2
IF mLinf > MaxRow() - 4
mLini := mLini + MaxRow() - 4 - mLinf
mLinf := mLini + Len( mMenuOpt ) + 2
ENDIF
mColf := mColi + 42
WOpen( mLini, mColi, mLinf, mColf, mTitulo )
Mensagem( "Selecione e tecle <ENTER>, <S> (Tem Acesso), <N> (Sem Acesso), <ESC> sai" )
DO WHILE .T.
FOR mCont = 1 TO Len( mMenuOpt )
@ mLini + 1 + mCont, mColi + 1 SAY " " + Pad( mMenuOpt[ mCont, 1 ], 31 ) + iif( Len( mMenuOpt[ mCont, 2 ] ) > 0, Chr(16), " " ) + " " + ;
iif( mMenuOpt[ mCont, 4 ], "SIM", "NAO" ) + " " COLOR iif( mCont == mOpc, SetColorFocus(), SetColorBox() )
NEXT
SetColor( SetColorNormal() )
mTecla := Inkey(0)
DO CASE
CASE mTecla == K_ESC
EXIT
CASE mSaiSetas .AND. ( mTecla == K_RIGHT .OR. mTecla == Asc( "6" ) .OR. mTecla == K_LEFT .OR. mTecla == Asc( "4" ) ) // setas
EXIT
CASE mTecla == K_LBUTTONDOWN
IF MROW() > mLini + 1 .AND. MROW() < mLini + 2 + Len( mMenuOpt ) .AND. MCOL() > mColi .AND. MCOL() < mColi + 38
mOpc := MROW() - mLini - 1
Keyboard Chr( K_ENTER )
ENDIF
CASE mTecla == K_RBUTTONDOWN
Keyboard Chr( K_ESC )
CASE mTecla == K_DOWN .OR. mTecla == Asc( "2" )
mOpc := iif( mOpc == Len( mMenuOpt ), 1, mOpc + 1 )
CASE mTecla == K_UP .OR. mTecla == Asc( "8" )
mOpc := iif( mOpc == 1, Len( mMenuOpt ), mOpc - 1 )
CASE mTecla == K_HOME .OR. mTecla == Asc( "7" )
mOpc := 1
CASE mTecla == K_END .OR. mTecla == Asc( "1" )
mOpc := Len( mMenuOpt )
CASE mTecla == Asc( "S" ) .OR. mTecla == Asc( "s" )
MudaAcess( mMenuOpt, mOpc, .T. )
CASE mTecla == Asc( "N" ) .OR. mTecla == Asc( "n" )
MudaAcess( mMenuOpt, mOpc, .F. )
CASE mTecla == K_ENTER
IF Len( mMenuOpt[ mOpc, 2 ] ) > 0
// se tem submenus, abre para os submenus
mMenuOpt[ mOpc, 4] := BoxAcesso( mLini + 1 + mOpc, mColi + 5, mMenuOpt[ mOpc, 2 ], 1, mMenuOpt[ mOpc, 1 ], .T. )
ELSE
// se não tem submenus, então só resta permitir por usuário
PCFG0050User( mMenuOpt[ mOpc, 3 ] )
ENDIF
ENDCASE
ENDDO
mReturn := .F.
FOR mCont = 1 TO Len( mMenuOpt )
IF mMenuOpt[ mCont, 4 ]
mReturn := .T.
ENDIF
NEXT
WClose()
RETURN mReturn
// pra modificar a opção, ou todos os submenus da opção
FUNCTION MudaAcess( mMenuOpt, mOpc, mModo )
LOCAL mCont
IF ValType( mMenuOpt[ mOpc, 3 ] ) != "B"
mMenuOpt[ mOpc, 4 ] := mModo
IF Len( mMenuOpt[ mOpc, 2 ] ) > 0
FOR mCont = 1 TO Len( mMenuOpt[ mOpc, 2 ] )
MudaAcess( mMenuOpt[ mOpc, 2 ], mCont, mModo )
NEXT
ENDIF
ENDIF
RETURN NIL
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Controle de Acesso
A tela gerada por essa rotina
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/

