MaximoAccess

Caro Usuário, antes de postar pela primeira vez, leia as regras do fórum.

Obrigado

Administração do MaximoAccess

Dicas Ms Access, Exemplos Ms Access, Codigos VBA Ms Access, SQL Ms Access


    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Eduardo Augusto
    Eduardo Augusto
    Novato
    Novato

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Brasil
    Mensagens : 13
    Registrado : 01/01/2016

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  Eduardo Augusto em 7/5/2019, 00:18

    Prezados amigos:

    Tenho um sistema em Access funcionando há 16 anos, numa rede de 10 computadores, estando o sistema dividido em back-end e front-end.

    Devido a algumas mudanças na legislação, tive que criar novas rotinas e, agora, a cada registro efetuado no Access ("registro finalizado"),  o VBA envia um script (uma hash) a um executável em Delphi ("AssinadorDelphi.exe"), que assina digitalmente a hash e salva o resultado num arquivo.txt numa determinada pasta do servidor (no texto: a mesma string com um enorme adendo no final). Em seguida, o VBA faz a leitura automática dessa hash assinada e gera o respectivo QRCode.
    Talvez seja interessante esclarecer que, ao ser acionado pelo VBA, o "AssinadorDelphi.exe" executa uma rotina que dura, no máximo, 3 segundos, liberando, em seguida, o arquivo.txt para o Access.

    Até esse ponto, a interação VBA-Delphi está funcionando perfeita e automaticamente. No entanto, o próximo passo a ser implementado está sendo um enorme desafio.

    Para a geração da assinatura digital em nome da empresa (mediante certificado digital tipo A1, instalado na CPU1), o arquivo.exe em Delphi deve obrigatoriamente ser executado nessa máquina.

    Portanto, eu preciso que as outras 9 máquinas tenham exatamente o mesmo poder de finalizar o registro, gerando a hash assinada e o QRCode, com o uso do único certificado digital que está instalado na CPU1. Esclareço ser (juridicamente)impossível instalar esse certificado digital em mais de uma máquina e, mesmo que isso fosse viabilizado mediante a utilização de algum "supercódigo", tal conduta configuraria um delito cibernético.

    De toda a leitura que fiz internet afora, parece-me que a solução está em fazer com que o VBA executado individualmente em cada máquina da rede acione remotamente o "AssinadorDelphi.exe" na CPU1 (via OpenSSH? TelNet? OpenShell?), de forma que a execução desse aplicativo ocorra na RAM da CPU1 e não na máquina cujo VBA emitiu o comando.

    O uso do TeamViewer para rodar o Access na CPU1, por exemplo, apesar de obter o resultado almejado (consegui isso em uma máquina há poucos minutos), não soluciona o problema (até cria outros), pois essa prática tornaria inútil a existência dos aplicativos Access front-end, uma vez que todas as máquinas rodariam um único aplicativo Access da CPU1, consumindo recursos e gerando riscos de perda de dados pela simultaneidade de uso.

    Imagino que possa haver "uma linha de comando" escondida na manga (do João Paulo, do Avelino Sampaio, do Sérgio Vieira, do Criquio, do Harysohn e de outras feras deste fórum) que permita acionar remotamente o "AssinadorDelphi.exe" via SSH, ou, talvez, a solução esteja na confecção de uma DLL ou de um outro app.exe em VB (C#, Python, etc) que sirva tão somente para abrir esse "buraco de minhoca", tão sonhado por Einstein e Nathan Rosen.

    Alguém poderia me dar uma dica?

    Obrigado.
    EA
    ahteixeira
    ahteixeira
    Moderador Global
    Moderador Global

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Portugal
    Mensagens : 6168
    Registrado : 15/03/2013

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  ahteixeira em 7/5/2019, 08:26

    Olá Eduardo Augusto,

    Não tenho conhecimento como se faz, mas na minha opinião o mais adequado seria ter um "webservice" no CPU1 disponível para chamada na sua rede.
    Assim os postos faziam o pedido ao servidor (CPU1) enviando os parâmetros necessários e o servidor dava a resposta (Hash)

    Abraço
    avatar
    zcarloslopes
    Intermediário
    Intermediário

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Portugal
    Mensagens : 161
    Registrado : 28/10/2010

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  zcarloslopes em 7/5/2019, 11:42

    Bom dia Augusto,

    Estas linhas de código já funcionam em tempos no Windows Server 2003, veja se ajuda:

    VBS:
    Código:
    'Run program or file

    Sub Run(ByVal sFile)
    Dim shell

        Set shell = CreateObject("WScript.Shell")
        shell.Run Chr(34) & sFile & Chr(34), 1, false
        Set shell = Nothing
    End Sub

    ' Execute the file MyFile.exe
    Run "C:\Programas\ccleaner\CCleaner.exe" /AUTO

    ' Open the file MyFile.doc in Word
    'Run "C:\My Documents\MyFile.doc"

    BAT:
    Código:
    @ECHO OFF
    ECHO CCleaner is cleaning your PC ...
    "C:\Programas\CCleaner\CCleaner.exe" /AUTO
    ECHO.
    ECHO Windows will be shutdown in 10 seconds ...
    ShutDown.exe-s-t10

    Abraço
    Eduardo Augusto
    Eduardo Augusto
    Novato
    Novato

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Brasil
    Mensagens : 13
    Registrado : 01/01/2016

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  Eduardo Augusto em 7/5/2019, 11:44

    Olá, Alvaro Teixeira.

    Muito obrigado pela sua gentil colaboração.
    Você poderia, por favor, esclarecer o que seria (e como poderia ser feito) um "webservice" no CPU1 disponível para chamada na rede?
    Pelo que entendi, o fluxo de dados não ocorreria necessariamente pela Internet, atuando esse "webservice" interna ou externamente, dependendo apenas das configurações.
    Devido a minha quase total ignorância nesse assunto, preciso de um pouco mais de dicas para poder pesquisar e aventurar-me na criação da rotina.
    Será que eu conseguiria adaptar o código de meu "AssinadorDelphi.exe" para transformá-lo nessa pseudo-webservice? Seria bem interessante...
    Se bem que não consigo imaginar a lógica dessa aplicação sem o uso de Telnet, SSH, MobaSSH ou algo do gênero. Talvez uma das linhas de código desse "webservice" por você sugerido seja exatamente a solução de meu problema.
    Ah, esclareço que não sou profissional da área de informática (nem da área de exatas), mas apenas um curioso que mexe com computador desde 1986; portanto, peço a todos que me perdoem pelos eventuais vacilos em meus questionamentos.

    Um abraço.
    EA
    ahteixeira
    ahteixeira
    Moderador Global
    Moderador Global

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Portugal
    Mensagens : 6168
    Registrado : 15/03/2013

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  ahteixeira em 7/5/2019, 12:34

    Olá a todos,

    Carlos Lopes, aparentemente esse código é para ser executado diretemente no servidor, confirme se estou enganado ou se realmente pode ser executado através de outro terminal (estação de trabalho).

    Eduardo Augusto Quanto a "webservice" é melhor dar uma pesquisa na net, no entanto encontrei este artigo que vai no seguimento do que pretende "executar em computador remoto", veja:
    docs.microsoft.com/en-us/sysinternals/downloads/psexec

    Outra questão, pode partilhar ou descrever o que faz comcretamente o "AssinadorDelphi.exe".

    Abraço a todos
    avatar
    zcarloslopes
    Intermediário
    Intermediário

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Portugal
    Mensagens : 161
    Registrado : 28/10/2010

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  zcarloslopes em 7/5/2019, 12:41

    Bom dia,

    Veja se o link abaixo serve para o efeito:

    rlmueller.net/Deploy.htm  
    [Antenção: Link externo deve-se colocar sem o h t t p s : / /]

    Abraço
    ahteixeira
    ahteixeira
    Moderador Global
    Moderador Global

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Portugal
    Mensagens : 6168
    Registrado : 15/03/2013

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  ahteixeira em 7/5/2019, 14:38

    Olá Carlos Lopes,

    Fica mais essa dica (desconhecia), ficamos aguardar o retorno do colega Eduardo Augusto.

    Abraço a todos
    Eduardo Augusto
    Eduardo Augusto
    Novato
    Novato

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Brasil
    Mensagens : 13
    Registrado : 01/01/2016

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  Eduardo Augusto em 9/5/2019, 20:55

    Prezados amigos:

    Agradeço imensamente a todas as contribuições.
    É incrível como as coisas aparentemente mais complexas são solucionadas com medidas bastante simples.
    Após muito ler sobre Telnet, SSH, Moba e me aventurar nessas plataformas, consegui solucionar a questão com a dica do Alvaro Teixeira: o PSExec.exe (e seu pacote PSTools).
    Um simples executável de 331 Kb e uma única linha de comando no "prompt" do Windows e tudo deu certo.

    Vejam a lógica que tive que executar:

    O código VBA (executado de qualquer máquina da rede) cria um arquivo.bat na CPU1 (computador com o certificado digital) com apenas uma única linha de comando:

    C:\Users\user\Sistema\Processamento\AssinadorDigital\AssinadorDelphi.exe --xx-- R1-008765(AZ) --xx-- 3132354551587548121212122125212523

    Percebam que o arquivo.bat tem uma linha de comando que aciona o arquivo executável (AssinadorDelphi.exe) e dois parâmetros separados por "algo identificável pelo código Delphi" (" --x-- ").
    O 1º parâmetro é o número do registro (R1-008765(AZ) e o segundo é a string (hash) codificada em bytes (3132354551...) para ser assinada digitalmente.
    Outro importante detalhe: o endereço da pasta onde está localizado o AssinadorDelphi.exe não está direcionado "pela rede" ("\\CPU1\Processamento"), mas sim localmente ("C:\Users\User..."), pois essa linha de comando não será executada pela rede, mas internamente na máquina hospedeira.

    Imediatamente após a criação desse arquivo, o código VBA executa esse arquivo.bat, mas de uma forma que sua execução ocorra na CPU1 e não na máquina do usuário.
    Para viabilizar isso, a utilização do prompt do Windows e do minúsculo executável PSExec.
    Eis a linha de comando, já substituídas as variáveis pelo seu valor, para facilitar a compreensão:

    Shell "PSExec \\192.168.1.10 -u usuario -p senhasecreta -i -h RI-008765(AZ).bat"

    Tentei usar o PSExec para acionar diretamente o AssinadorDelphi.exe pelo código VBA, mas não obtive sucesso. Talvez a presença dos parâmetros tenha sido o complicador, mas não tive como confirmar com segurança, já que com o apoio do arquivo.bat deu certo. Consegui assinar digitalmente os registros e obter o QRCode da hash assinada.

    O único efeito colateral dessa minha estratégia, que certamente irá me dar um pouco de transtorno, é a inexplicável demora entre o acionamento do PSExec e ao acionamento do Assinador Digital.
    O processo demora exatos 30 segundos!!!
    Se alguém tiver alguma dica para minorar essa questão, ficarei ainda mais satisfeito.

    Mais uma vez, obrigado a todos.
    EA
    Eduardo Augusto
    Eduardo Augusto
    Novato
    Novato

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Brasil
    Mensagens : 13
    Registrado : 01/01/2016

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  Eduardo Augusto em 10/5/2019, 01:06

    Prezado Alvaro Teixeira, Carlos Lopes e demais colegas:


    Inicialmente, agradeço a Carlos Lopes pela dica do Deploy.

    Pareceu-me ser a solução (e até acredito que seja), mas, na correria, eu não soube utilizar o código.

    Tenho o Visual Studio 2017 (recém-instalado na máquina para poder resolver meus problemas com o software) e tentei encaixar esse código em cada uma das dezenas de formas (pela 1ª vez, senti saudades do tempo em que todo aplicativo tinha apenas uma única opção de uso), mas em nenhuma delas ele se apresentou viável. De todas,  apenas umas duas ou três reconheceram o termo "Dim" como declarador de variáveis (confesso que isso foi uma enorme surpresa para mim).

    Após muitas tentativas (todas em vão), o local em que o código se portou aparentemente bem foi no VBA do Access, mas infelizmente portar-se bem e ser funcional nem sempre são qualidades que andam juntas.

    Por fim, tive que desistir de compreender o código, pois a dica do PSExec.exe do Alvaro Teixeira solucionou a questão (e de forma surpreendentemente simples!).

    Mesmo assim, muito obrigado pela sua colaboração.


    Respondendo, agora, uma questão mais pontual do Alvaro Teixeira: detalhes sobre o "AssinadorDelphi.exe".

    Trata-se de um aplicativo que elaborei em Delphi (que só descobri ser uma linguagem de programação há menos de um mês). Entender Delphi nesse curto período só foi possível graças aos vídeos tutoriais do Youtube; e escrever o aplicativo em si, só foi possível graças à maravilhosa ajuda de participantes de um outro fórum (Projeto ACBr, voltado para escrituração contábil fiscal - Nota Fiscal Eletrônica).

    Esse aplicativo teria inicialmente o formato de uma DLL, mas tive que optar por criar um executável pelo fato de o VBA não ter aceitado a interconexão com uma DLL Delphi (ou melhor, pelo fato de eu ter falhado na tentativa de conectar essa DLL ao VBA).

    Em resumo, o AssinadorDelphi recebe a string (hash) enviada pelo VBA; no caso, pelo 2º parâmetro da linha de cmdo do arquivo.bat (conforme explanei na postagem anterior e que aqui repito):


    • C:\Users\user\Sistema\Processamento\AssinadorDigital\AssinadorDelphi.exe --x-- R1-008765(AZ) --xx-- 3132354551587548121212122125212523...(string bem longa)

      1º parâmetro: R1-008765(AZ): nº do registro que está sendo assinado
      2º parâmetro: 3132354551587548121212122125212523...: hash a ser convertida em SHA256 e assinada digitalmente
      Separadores: --x--  e  --xx--: separadores por mim escolhidos para que o AssinadorDelphi.exe identifique os dois parâmetros.
      Observação: o uso-padrão do "espaço" como separador (facilmente identificado por qualquer código) falhou pelo fato de muitas pastas terem espaços em seus nomes. Optei por criar um novos identificadores a tentar me aventurar na insana missão de alterar os nomes das pastas-padrão do Windows.


    Abaixo o código completo em Delphi do Assinador Digital, que tenho a satisfação de disponibilizar a todos:

    Código:

    unit AssinadorDelphi;

    interface

    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, ACBrDFe, ACBrDFeSSL,
      ACBrDFeWinCrypt, ACBrConsts;  //este último item (ACBrConsts) é um paliativo para corrigir erro de OLE no ACBrCAPICOM

    type
      TFormNulo = class(TForm)                         //Linhas inúteis do código que não pude apagar
        Button1: TButton;                              //pois, minha rotina não usa nenhum formulário;
        procedure FormCreate(Sender: TObject);         //no entanto, não soube criar o aplicativo sem Form
        procedure Button1Click(Sender: TObject);       //portanto, linhas "inúteis com certa utilidade"

      private
        { Private declarations }
      public
        { Public declarations }
      end;

    var
      FormNulo: TFormNulo;
      FACBrDFe: TACBrDFe;
      ato: pchar;
      arq: textfile;

    implementation
       {$R *.dfm}

    procedure TFormNulo.Button1Click(Sender: TObject);  
    begin                                       //linhas "inúteis com certa utilidade"
       exit;                                    //linhas "inúteis com certa utilidade"
    end;                                        //linhas "inúteis com certa utilidade"

    procedure TFormNulo.FormCreate(Sender: TObject);
       var cmdo : pchar;
       var ato : pchar;
       var ato1 : pchar;
       var assin : anstring;
       var num1 : integer;
       var num2 : integer;
       var pasta : pchar;

    begin
      cmdo := getcommandline;                 //coloca em uma variável o comando que acionou o executável
      num1 := Pos(' --x-- R', cmdo) + 7 ;     //posição inicial do 1º parâmetro: nº do registro
      num2 := num1 + 20;                      //posição inicial do 2º parâmetro: hash a ser assinada

      ato := pchar(copy(cmdo, num2, Length(cmdo)));      //extrai o 2º parâmetro (hash a assinar)

      if ato<>nul then
       begin
          ato1 := pchar(copy(cmdo, num1, num2-7));       //extrai o 1º parâmetro (nome do registro)
          pasta:= pchar('C:\Users\User\Sistema\Processamento\AssDig\' + ato1 + '.txt');

             //Observação importante: as linhas abaixo são o cerne do assinador digital
             //elas só têm esse poder graças a outras 'units' em Delphi (códigos longos e bem complicados)
             //que foram referenciadas lá no início no campo USES
             //são elas: ACBrDFe, ACBrDFeSSL e ACBrDFeWinCrypt
             //todas de autoria do Projeto ACBr, que disponibiliza gratuitamente esses componentes
             //esses componentes (ao lado de centenas de outros, todos voltados para escrituração fiscal eletrônica)
             //vêm com um instalador que os insere automaticamente no programa Delphi da máquina

             FACBrDFe := TACBrDFe.Create(Application);
             FACBrDFe.Configuracoes.Geral.SSLLib:= libWinCrypt;

             //identificação do certificado a ser utilizado para a assinatura digital
             FACBrDFe.Configuracoes.Certificados.NumeroSerie := 'xxxxx-SeuNumeroSeriexxxxxx';    

             //senha do certificado identificado acima (linha dispensável no caso de A1 com senha liberada na máquina)
             FACBrDFe.Configuracoes.Certificados.Senha := 'senhasecreta';                          

             //processo de assinatura digital da hash (constante da variável 'ato')
             assin := FACBrDFe.SSL.CalcHash(ato, dgstSHA256, outBase64, True);
             FACBrDFe.Free;


          //criação de um arquivo.txt com uma única linha (a hash assinada digitalmente)
          //o arquivo será salvo numa pasta apropriada,
          //estando o VBA preparado para fazer sua leitura 30 segundos depois de ter acionado toda esta parafernália
          AssignFile (arq, pasta);
          Rewrite(arq);
          Writeln(arq,assin);
          CloseFile(arq);
          FormNulo.close;
          postMEssage(Handle, WM_CLOSE, 0, 0);
       end;

       begin
          postMEssage(Handle, WM_CLOSE, 0, 0);
          exit;
       end;

    end;

    begin

    end.

    Espero que esse código seja útil a outras pessoas e que ninguém passe pelo sufoco que eu passei..., ou melhor, que eu continuo passando, pois ainda faltam alguns itens complexos para eu poder finalizar o programa.

    Mais uma vez agradeço a todos pela maravilhosa contribuição.
    Apesar de haver espaço para mais importantes deliberações, julgo ser conveniente marcar o tópico como resolvido, para dar oportunidade a outros consulentes de contar com a atenção e a inestimável colaboração dos doutos colegas.

    Muito obrigado!
    EA

    ...
    ahteixeira
    ahteixeira
    Moderador Global
    Moderador Global

    Respeito às Regras 100%

    Sexo : Masculino
    Localização : Portugal
    Mensagens : 6168
    Registrado : 15/03/2013

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  ahteixeira em 10/5/2019, 12:37

    Olá a todos,

    Eduardo Augusto, antes de tudo obrigado pelo retorno detalhado e partilha do código.
    Fico feliz por ter conseguido, independentemente da "demora", já é um avanço!

    Relativamente à utilização do "bat" para ultrapassar o erro na passagem de parametros no comando (relatado na mensagem nº Cool eu normalmente tenho solucionado a questão da aspa dupla com o chr(34) fica a dica e abaixo um código de exemplo:
    Código:
    Private Sub Form_Close()
        'para apagar imagens ao sair
        Dim tmpJpg
        tmpJpg = CurrentProject.Path & "\" & "~tmp*.jpg"
        Shell "cmd /c del " & Chr(34) & tmpJpg & Chr(34), 0
    End Sub

    Após a leitura da última mensagem, aparentemente e se não me engano, o "AssinadorDelphi.exe" está a criar uma HASH, método utilizado aqui em Portugal nos programas informáticos "certificados".
    Como alternativa talvez possa usar o OpenSSL que é gratuíto e talvez possa ter uma performance melhor.
    Partilho manual que tem exemplo de Criação do Par de Chaves Privada/ Pública e Certificado:
    cld.pt/dl/download/c183546d-1479-4283-812d-7a1152ddbb67/Oficio_Circulado_50001.pdf#page=13

    Nota: Para quem desejar ter um programa certificado em Portugal o link acima é uma excelente ajuda.

    Abraço a todos

    Conteúdo patrocinado

    [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede Empty Re: [Resolvido]VBA - Executar Remotamente um Arquivo.Exe na Rede

    Mensagem  Conteúdo patrocinado


      Data/hora atual: 18/7/2019, 17:09