Ir para conteúdo
  • Cadastre-se

dev botao

  • Este tópico foi criado há 1932 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

  • Fundadores
Postado

Olá pessoal,

Introduzi no componente ACBrPosPrinter, um novo mecanismo de acesso a Impressora

Agora poderemos acessar algumas impressoras, usando a Sintaxe:

  ACBrPosPrinter1.Porta := 'DLL:MARCA';

Onde MARCA, será o nome da Marca do Fabricante da Impressora... Até o momento, temos suporte para as marcas "ELGIN", e "EPSON"

A ideia por traz dessa nova sintaxe de Porta, é permitir usar a DLL/SO do Fabricante, para Imprimir diretamente na Impressora...

Ok.. o ACBrPosPrinter,  já conseguia acessar impressoras Não Fiscais, pela Porta USB, usando a Sintaxe "RAW:"

 ACBrPosPrinter1.Porta := 'RAW:Nome da Impressora no Windows';

 

Mas então porque desenvolvemos essa nova forma de acesso ?

A nova sintaxe "DLL:", tem algumas vantagens, em relação a sintaxe "RAW:"

  • Não depende da instalação do Driver de Spool da Impressora.. (note porém, que em alguns casos, o Driver de Spool não pode estar instalado, pois ele bloqueia o acesso a USB)
  • Podemos Ler Informações da Impressora (o que não é possível no modo RAW)

Entretanto, como foi dito antes, dependemos de DLL exclusiva do fabricante, para o acesso a Impressora pela USB...

  • Quais são essas DLLs ?
  • Para onde eu devo copiá-las ?

Vejamos como foi descrito no ACBrSerial-change-Log.txt

Citar

Data: 01/02/2019
-- ACBrPosPrinter --
[*] Melhorias na detecção de Porta Ativa e Controle de Porta
[+] Adicionado novo suporte a Impressoras através da Porta USB. Agora o
    ACBrPosPrinter aceita a sintaxe de portas como:  "DLL:MARCA", onde
    "MARCA" é o nome do Fabricante.
    Com isso o ACBrPosPrinter usará a DLL do fabricante para acesso a Impressora,
    pela porta USB.

-- ACBrEscPosHook --
[+] Implementado Classe genérica para criação de Hooks

-- ACBrEscPosHookElginDLL --
[+] Implementação de Hook com as DLLs da "ELGIN":  HprtPrinter.dll, hprtio.dll
    Use em Porta := "DLL:ELGIN", e mantenha as DLLs indicadas na mesma pasta do
    seu Executável

-- ACBrEscPosHookEpsonDLL --
[+] Implementação de Hook com a DLL da "EPSON":  InterfaceEpsonNF.dll
    Use em Porta := "DLL:EPSON", e mantenha a DLL indicada na mesma pasta do
    seu Executável

    (por: DSA)

Creio que isso responde as duas perguntas, correto ?

Você pode encontrar as DLLs no nosso SVN, na pasta: \ACBr\DLLs\PosPrinter, ou ainda pela Web: http://svn.code.sf.net/p/acbr/code/trunk2/DLLs/PosPrinter/

Você pode ainda baixar uma versão do Demo PosPrinterTeste,  atualizada, compilado em Lazarus/FPC no link abaixo:

 

 

Como funciona essa nova técnica ?

Quem faz todo acesso as Portas suportadas pelo ACBr, é um subcomponente chamado ACBrDevice, e há um bom tempo, esse componente já possui uma possibilidade de Integração por Hooks

O que é Hook ?
https://pt.wikipedia.org/wiki/Hooking

A ideia por trás dos Hooks, é instalar ganchos, em eventos, que nos permitam interceptar algumas ações e chamadas... Veja esse trecho de código

  FDevice.HookAtivar := PosPrinterHookAtivar;
  FDevice.HookDesativar := PosPrinterHookDesativar;
  FDevice.HookEnviaString := PosPrinterHookEnviaString;
  FDevice.HookLeString := PosPrinterHookLeString; 

Aqui instruímos o subcomponente ACBrDevice, a chamar nossos eventos, quando ele precisar  "Ativar", "Desativar" uma porta e também quando ele for "EnviarString" e "LeString", de uma determinada porta...

Então no interior do componente ACBrPosPrinter, implementamos os eventos indicados acima (PosPrinterHookAtivarPosPrinterHookDesativar, etc) ...

Com isso, o ACBrDevice executará um código nosso, ao invés do que ele normalmente executaria...  Veja que dentro dos eventos de ativação e desativação usamos uma Classe de Hook (leia mais abaixo)

procedure TACBrPosPrinter.PosPrinterHookAtivar(const APort: String; Params: String);
begin
  if Assigned(FHook) then
    FHook.Open(APort);
end;

procedure TACBrPosPrinter.PosPrinterHookDesativar(const APort: String);
begin
  if Assigned(FHook) then
    FHook.Close;
end;  

 

FHook por sua vez, é uma variável interna ao ACBrPosPrinter, que contem uma Classe de Hook (TACBrPosPrinterHook), e implementa os comandos necessários, para transmitir essas ações, a DLL do fabricante...

Veja o exemplo abaixo, como fica a implementação dos Hooks de  Ativar e Desativar, da ELGIN... observe que chamamos métodos Externos, da DLL da Elgin, como: "PrtPortOpenW" e "PrtPortClose"

procedure TElginUSBPrinter.Open(const APort: String);
var
  errorNo: Integer;
begin
  if Connected then
    Exit;

  inherited Open(APort);

  try
    errorNo := xPrtPortOpenW(FPrinter, WideString(fpPort));   // <------- A Q U I -------
    if (errorNo <> E_SUCCESS) then
      raise Exception.CreateFmt(CERROR_OPEN, [fpPort, fpPrinterName]);
  except
    fpConnected := False;
    fpPort := '';
    raise;
  end;
end;

procedure TElginUSBPrinter.Close;
var
  errorNo: Integer;
begin
  if not Connected then
    Exit;

  errorNo := xPrtPortClose(FPrinter);          // <------- A Q U I -------
  if (errorNo <> E_SUCCESS) then
    raise Exception.CreateFmt(CERROR_CLOSE, [fpPort, fpPrinterName]);

  inherited Close;
end;

 

Com isso, conseguimos usar a DLL do Fabricante, para estabelecer um túnel entre o ACBrPosPrinter e o equipamento...

 

Como posso implementar um Hook para um novo modelo ?

Os Primeiros passos, são verificar:

  • Se o Fabricante disponibiliza uma DLL para acesso direto ao equipamento (sem depender do Spooler)
  • Se há nessa DLL, um método que nos permita Escrever e Ler Dados da Porta USB

Ou seja, não precisamos de métodos de alto nível, que façam a formatação de caracteres, ou manipulem a impressora... Pois continua sendo o ACBrPosPrinter, quem montará toda a Sintaxe de comandos a serem enviados para a Impressora, usando a linguagem Esc/Pos... e igualmente, será o ACBrPosPrinter que fará a leitura de respostas, quando for necessário...

Na DLL da Elgin, temos um ótimo exemplo de método para isso...

function PrtDirectIO(printer:Pointer;    //  Ponteiro com a Impressora instanciada por PrtPrinterCreatorW
                     writeData:PByte;    //  Buffer com dados a serem enviados
                     writeNum:integer;   //  Número de Bytes em "writeData" (tamanho do Buffer)
                     readData:PByte;     //  Ponteiro com o Retorno a ser Lido  (Buffer de saída)
                     readNum:integer;    //  Numero de bytes disponíveis para escrita em "readData" (tamanho disponível no Buffer de Saída)
                     preadedNum:PInteger //  Número de bytes realmente escritos em "readData"
                    ): Integer; cdecl;   //  Status de retorno  E_SUCCESS = 0;

 

Tendo isso em mãos, podemos criar uma cópia de uma das Units já existentes, como por exemplo a Unit ACBrEscPosHookElginDLL.pas, e implementar o suporte usando a nova DLL, e efetuar os ajustes referente a nova Marca

 

  • Curtir 11
  • Obrigado 3
Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

  • 10 meses depois ...
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.

The popup will be closed in 10 segundos...
The popup will be closed in 10 segundos...