Aplicações Externas no AdvPL – Parte 02

Introdução

No tópico anterior, vimos um exemplo de chamada de aplicação externa ao AdvPL via Smartclient, usando uma DLL. As mesmas regras da DLL valem para criar uma biblioteca de objetos compartilhados (Shared Object), para ser usada com o SmartClient Linux. Neste tópico, antes de ver alguns recursos mais avançados de DLL, vamos ver alguns comandos para chamar diretamente uma aplicação externa executável através do SmartClient.

Para a execução de aplicativos na máquina onde está sendo executado o SmartClient, o AdvPL disponibiliza três funções: WinExec(), WaitRun() e ShellExecute(). Cada uma delas possui parâmetros, atributos e comportamentos distintos, aplicáveis a diversas situações. Os detalhes de cada função estão documentados na TDN, nos links disponibilizados nas referências deste post. Neste tópico, o foco vai ser na utilidade, pontos comuns e diferenças de cada uma.

Função WinExec

Dispara a execução de uma aplicação externa ao SmartClient, sem aguardar por retorno ou finalização. Pode ser chamado qualquer aplicação na máquina, sem informar o PATH completo do arquivo, desde que a aplicação esteja em algum diretório especificado na variável de ambiente PATH da máquina onde está sendo executado o SmartClient.

Função WaitRun

Permite a execução de uma aplicação externa ao SmartClient, aguardando pelo término da aplicação. Esta particularidade pode não ser respeitada quando o SmartClient está sendo executado em uma máquina com Windows 10, por exemplo, devido a mudanças entre as versões do sistema operacional. Da mesma forma que a WinExec, podemos ou não informar o PATH completo da aplicação a ser executada, sendo possível omitir o caminho completo da aplicação caso ela esteja na variável de ambiente PATH da máquina onde o SmartClient está sendo executado. Adicionalmente, na função WaitRun(), pode ser especificado um parâmetro para a execução de uma aplicação sem que seja aberta uma janela de interface, ou pode ser iniciada a aplicação em uma janela minimizada.

Função ShellExecute

De modo similar a WinExec, ela apenas dispara uma aplicação. Porém, ela permite vários parâmetros adicionais, e inclusive permite outras operações relacionadas a arquivos, URLs, documentos e afins, onde o sistema operacional pode utilizar diretamente a aplicação default para uma determinada ação. Por exemplo, podemos solicitar a abertura de uma URL de um WebSite, informando o endereço HTTP, e o sistema operacional vai utilizar para esta ação o Browser de Internet default configurado para abrir endereços HTTP. A função ShellExecute não espera pelo término da aplicação iniciada.

Exemplo 01

Um cliente possui um Web Site de venda de seus produtos, onde existe uma página de consulta por código, que pode receber como parâmetro o código do produto desejado pela URL. E, no seu cadastro de produtos no ERP, ele têm o código do produto disponibilizado no site. Ele gostaria de criar uma função em AdvPL, que recebesse um código WEB do Produto, e abrisse uma página do navegador, na estação do usuário do Smartclient, trazendo na tela a consulta do produto no site.

A alternativa mais elegante é usar a função ShellExecute(), montando a URL de acesso usando o código fornecido, e deixando o sistema operacional abrir a página do site no Navegador de Internet padrão da máquina do usuário. Veja o exemplo abaixo:

#include 'shell.ch'

User Function ConsWeb(cCodWeb)
Local cUrl := 'http://meusite.com.br/"
Local cPage := 'consprod.php?cod='+cCodWeb

ShellExecute('open',cUrl+cPage,"","",SW_NORMAL)

Return

Exemplo 02

Vamos partir do primeiro exemplo, porém eu quero que a URL em questão sempre seja aberta pelo Google Chrome, mesmo que ele não seja o navegador default. Para isso, basta endereçarmos a execução do “Chrome.EXE”, e passamos como parâmetro a URL a ser aberta. nem preciso dizer que este é um exemplo didático, e que o sucesso dessa abordagem exige que a máquina onde está sendo executado o SmartClient tenha o Google Chrome instalado.

#include 'shell.ch'

User Function ConsWeb2(cCodWeb)
Local cUrl := 'http://meusite.com.br/"
Local cPage := 'consprod.php?cod='+cCodWeb

ShellExecute('open','chrome.exe',cUrl+cPage,"",SW_NORMAL)

Return

Exemplo 03

Precisamos executar um comando qualquer do sistema operacional, ou um aplicativo de linha de comando, onde não há passagem de parâmetros por interface, apenas por linha de comando, e o resultado deste comando é uma saída de texto em tela. Por exemplo, um comando “dir”, ou um “ifconfig” — para obter detalhes das interfaces de rede. Normalmente, quando executamos um comando assim pelo prompt de comando do sistema operacional, podemos direcionar a saída de tela para um arquivo em disco, colocando no final do comando um sinal de maior “>” , seguido do nome de um arquivo, que será criado em disco na pasta atual.

Porém, este direcionamento em arquivo é tratado apenas pelo interpretador de comandos, isto é, não funciona se você tentar usar em um Winexec(), WaitRun() ou ShellExecute(). Mas não precisa entrar em pânico, existe uma alternativa: Basta montar uma chamada direta para o interpretador de comandos (CMD.EXE), passando o comando original para ser executado através do interpretador de comandos.

Por exemplo, queremos executar um “ifconfig” na máquina onde está o SmartClient, para obter detalhes das interfaces de rede disponíveis. E, como não há como recuperar a string retornada direto pela chamada, fazemos uma saída em arquivo.

ifconfig > netconfig.txt

Porém, para executar esta instrução, e ela realmente gerar o arquivo em disco com o resultado, encapsulamos a chamada com o CMD.EXE, ficando assim:

cmd /c "ifconfig > netconfig.txt"

Agora, vamos ao exemplo prático, para recuperar as informações de configuração de rede da máquina do SmartClient. Caso a função não consiga recuperar as informações por qualquer razão, ela retorna uma string em branco. Assumimos que o arquivo “netconfig.txt” será gerado na pasta de trabalho do executável do SmartClient, então usamos a função GETREMOTEININAME() para descobrir o path completo do SmartClient, para copiar o arquivo gerado e copiar para uma pasta no APPServer, ou mesmo ler o arquivo diretamente usando o AdvPL, e posteriormente removendo o arquivo do disco.

User Function GetNetCfg()
Local cExec := 'cmd /c "ifconfig > netconfig.txt"'
Local cRet := ''
Local cRmtPath

// Identifica o PAth do SmartClient na maquina remota 
// a partir do path do arquivo smartclient.ini
cRmtPath := GETREMOTEININAME()
cRmtPath := left(cRmtPath,rat('\',cRmtPath))

// Executa o comando para chamar o ifconfig 
// e gerar o arquivo "netconfig.txt"
WaitRun(cExec,0)

If file(cRmtPath+'netconfig.txt')
 // O arquivo foi gerado, lê direto com MEMOREAD
 // E remove o arquivo do disco 
 cRet := memoread(cRmtPath+'netconfig.txt')
 ferase(cRmtPath+'netconfig.txt')
Endif

Return cRet

Outros Usos

É claro, existem limitações na passagem de parâmetros para uma aplicação executável ( Se eu não me engano a linha de comando total não pode ser maior que 255 bytes, e se a operação a ser executada é vital para garantir a continuidade do processo, garantir a execução com sucesso ou até descobrir onde houve falha na execução pode se tornar um problema. Para questões desta ordem, você pode fazer uma DLL para encapsular as chamadas e proteger com o que você achar necessário. Para execuções simples, que não precisam desse aparato todo, Shellexecute(), WaitRun() e WinExec() dão conta do recado.

Restrições

Quando voce usa WaitRun() ou WinExec(), se você fizer uma chamada direta a um comando de sistema operacional ou outro aplicativo de linha de comando, que tenha alguma parada de interface para solicitar entrada de dados ou confirmação de usuário, como não será aberta no terminal nenhuma janela de sistema operacional para dar um contexto de entrada para a aplicação, o prompt de comando vai ficar preso na memoria, até que o computador seja reiniciado ou o processo da aplicação seja derrubado da memória pelo Gerenciador de Tarefas do Windows.

Um exemplo clássico é criar um arquivo de lote (extensão “.bat”), e usar dentro dele uma instrução “pause”. Pronto, rodou isso com WaitRun(), seu SmartClient fica esperando pra sempre uma aplicação externa que não vai voltar nunca. Se você usar WinExec(), o programa AdvPL segue a vida, mas o processo iniciado na máquina remota para rodar o arquivo de lote fica preso na memória, até ser derrubado ou o usuário do computador fazer um logoff do sistema operacional ou reiniciar o equipamento. Se você executar isso pelo ShellExecute(), uma janela do interpretador de comandos será aberta, e você terá visão e interação com a aplicação em lote sendo executada.

Existem aplicações como o 7Zip, WinZip, WINSCP e afins, que embora sejam aplicações com interface gráfica, elas podem ser chamadas em modo ‘batch’, isto é, por linha de comando, sem interface. Com isso, por exemplo, você pode usar uma aplicação externa para transferir um arquivo para um servidor, gerar um pacote compactado de arquivos para enviar ao servidor, usar aplicações externas para fins específicos de integração com outras interfaces ou mesmo dispositivos.

Conclusão

Com estes três comandos, já dá pra fazer muita coisa. O modelo de chamada de aplicação externa é muito interessante, pois não compartilha a mesma área de memória do SmartClient, a aplicação é executada diretamente pelo sistema operacional, e nada impede de você criar a sua aplicação externa para atender a sua necessidade. Quando a integração envolve a chamada de diversas funções ou diversas vezes a mesma aplicação em curtos intervalos de tempo, pode ser mais vantajoso gastar um pouco mais de tempo e fazer a integração com DLL.

Espero que este post ajude a todos que desenvolvem em AdvPL a facilitar o processo de integração com outros sistemas, e desejo novamente a todos TERABYTES de SUCESSO 😀

Referências

http://tdn.totvs.com/display/tec/WinExec
http://tdn.totvs.com/display/tec/WaitRun
http://tdn.totvs.com/display/tec/ShellExecute

Anúncios

Um comentário sobre “Aplicações Externas no AdvPL – Parte 02

  1. Boa tarde!!! Estou tentando fazer uso dos comandos acima para impressão direta em uma porta LPT1 (mapeando a mesma via NET USE)
    Se executo o smartclient passando como parâmetro o programa inicial funciona..
    Se coloco na seção OnStart do appserver ou no schedule do sistema, não vai.. a função é executada porém não manda nada para a impressora..

    tentei da seguinte forma (caminho completo do cmd, só cmd, caminho completo do diretório onde está o txt, apenas a partir da protheus data.. enfim..:

    ShellExecute(“Open”, “C:\Windows\System32\cmd.exe”, ” /k copy C:\TOTVS\MICROSIGA\PROTHEUS_DATA\IMPETQ\” + UPPER(cFile) + “.TXT LPT1 “, “C:\TOTVS\MICROSIGA\PROTHEUS_DATA\IMPETQ\”, 1)

    WinExec(“cmd /c copy C:\TOTVS\MICROSIGA\PROTHEUS_DATA\IMPETQ\” + UPPER(cFile) + “.TXT LPT1”)

    Obrigado!!

    Marcio Rodrigo Lapidusas

    Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s