Enviar comandos para impressoras de etiquetas usando C#

Neste tópico vou mostrar como enviar comandos para uma impressora de etiquetas usando o Código C# do Formulário Dinâmico.

A linguagem utilizada vai depender do suporte oferecido pela impressa:

  • ZPL - Zebra Programming Language
  • DPL - Datamax Programming Language
  • EPL – Eltron Programming Language
  • IPL – Intermec Programming Language

Ou ainda as linguagens de emulação:

  • PPLA – Printer Programming Language A
  • PPLB – Printer Programming Language B

image

Infelizmente, eu não tive a oportunidade de executar este código pessoalmente pois não tenho uma impressora de etiquetas para testar, mas ajudei outras pessoas a fazer essa implementação a partir do código que será apresentado aqui, e funcionou!

Exemplo Simples

Primeiro, vamos começar com um exemplo simples: teremos um campo do tipo TextBox com a propriedade “multilinha” habilitada. Neste campo, vamos informar os comandos e clicar em um campo do tipo Button para enviá-los à impressora.

Campos

  • txtComando - Campo do tipo TextBox e com a propriedade “multilinha” habilitada

  • btnExecutar - Camo do tipo Button, que quando clicado vai enviar o comando para a impressora.

Variáveis

  • ip - Variável do tipo Text que receberá o IP da impressora na rede.

  • porta - Variável do tipo Number que receberá a Porta da impressora.

  • temperatura - Variável do tipo Text que receberá a temperatura que será usada na impressão, no formato especificado pelo fabricante.

Procedimentos

  • btnExecutar_Click - Procedimento que será vinculado ao evento Click do botão btnExecutar.

    • Neste procedimento, vamos preencher as variáveis e em seguida executar o código C# descrito no próximo item.

Código C#

O código C# abaixo deve ser executado através da ação “Executar Código C#” no procedimento “btnExecutar_Click”:

using System.Data.Common;
using LATROMI.Extensions;

var ip = (string)Variables["ip"].Value;
var porta = (int)Variables["porta"].Value;
var temperatura = (string)Variables["temperatura"].Value;
var comando = (string)Fields["txtComando"].Value;

if (string.IsNullOrEmpty(ip))
    throw new InvalidOperationException("Impressora não informada.");
    
if (string.IsNullOrEmpty(temperatura))
    throw new InvalidOperationException("Temperatura não informada.");

if (string.IsNullOrEmpty(comando))
    throw new InvalidOperationException("Informe um comando para enviar para a impressora.");

using (var client = new System.Net.Sockets.TcpClient())
{
   var serverEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(ip), porta);
   client.Connect(serverEndPoint);

   using (var clientStream = client.GetStream())
   {
       var encoder = new System.Text.ASCIIEncoding();
       byte[] buffer = encoder.GetBytes(comando);
       clientStream.Write(buffer, 0, buffer.Length);
       clientStream.Flush();
   }
}

Pronto! Informando o código corretamente, deve ser possível realizar a impressão.

Exemplo Avançado

No exemplo anterior, implementamos uma rotina simples, mas que é útil para testes.

Agora, vamos implementar um cenário mais próximo da realidade, aplicável a um ambiente de produção.

Considerando que ainda teremos as mesmas variáveis vamos implementar um código C# com o seguinte objetivo:

  1. Executar um SELECT no banco de dados e retornar os dados que serão plotados na impressão.

  2. Percorrer cada registro retornado e montar o código de impressão referente a cada um.

  3. Após acumular 20 comandos de impressão, vamos enviá-los para uma fila para serem enviados para impressora no final do processo. Esses 20 comandos serão enviados de uma só vez para a impressora. Você pode “granular” esses comandos em uma quantidade maior ou menor. A intenção é não enviar uma quantidade de comandos tão grande que possa travar ou causar um Timeout.

  4. Depois que terminar de percorrer todos os registros, vamos enviar os comandos da fila uma a um para a impressora.

Vamos lá!

using System.Data.Common;
using LATROMI.Extensions;

// Dicionário que vai receber os valores das colunas do registro retornado pelo SQL
var rDados = new Dictionary<string, object>();

var ip = (string)Variables["ip"].Value;
var porta = (int)Variables["porta"].Value;
var temperatura = (string)Variables["temperatura"].Value;

// Fila de comandos
var printQueue = new Queue<string>();

// Quantidade de comandos que serão enviados de uma só vez para a impressora
int stepSize = 20; 

if (string.IsNullOrEmpty(ip))
    throw new InvalidOperationException("Impressora não informada.");
    
if (string.IsNullOrEmpty(temperatura))
    throw new InvalidOperationException("Temperatura não informada.");

// Select para buscar os dados que serão impressos
var cmdText = new StringBuilder();
cmdText.AppendLine("SELECT");
cmdText.AppendLine("*");
cmdText.AppendLine("FROM tabela");
cmdText.AppendLine("WHERE id = 123456");

// NOTA: Passar o nome da conexão do LATROMI como parametro no método Database.CreateConnection("_______")
using (var connection = Database.CreateConnection("Nome da minha conexão no LATROMI"))
{
    // Abre a conexão
    connection.Open();

    // Percorre todos os registros e monta os comandos que seram enviados à impressora
    using(var cmd = connection.CreateCommand())
    {
        cmd.CommandText = cmdText.ToString();
        
        using (var dr = cmd.ExecuteReader())
        {
            int fieldCount = dr.FieldCount;
            while (dr.Read())
            {
                // Copia todos os valores do DataReader para o dicionário
                for (int i = 0; i < fieldCount; i++)
                {
                    rDados.Add(
                        dr.GetName(i),
                        Convert.IsDBNull(dr.GetValue(i)) ? null : dr.GetValue(i)
                        );
                }
    
                // Exemplo de comando DPL meramente ilustrativo. Informe outro código.
                // NOTA: Para informar caracteres especiais basta converter o número 
                //       da tabela ascii para "char" como nas 3 primeiras linhas
                var dataToSend = new StringBuilder()
                .AppendLine(((char)2).ToString() + "n")
                .AppendLine(((char)2).ToString() + "f000")
                .AppendLine(((char)2).ToString() + "L")
                .AppendLine("H" + temperatura)
                .AppendLine("...")
                .AppendLine("..." + rDados["select_campo1"])
                .AppendLine("..." + rDados["select_campo2"])
                .AppendLine();
    
                // Adiciona na fila
                printQueue.Enqueue(dataToSend.ToString());
                
                // Limpa o dicionário com os campos
                rDados.Clear();
            }
            dr.Close();
        }
    }

    // Percorre a lista com os comandos a serem enviados para a impressora
    while (printQueue.Any())
    {
        using (var client = new System.Net.Sockets.TcpClient())
        {
            var serverEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(ip), porta);
            client.Connect(serverEndPoint);

            using (var clientStream = client.GetStream())
            {
                for (int i = 0; i < stepSize; i++)
                {
                    // Remove da fila e envia para impressora
                    var encoder = new System.Text.ASCIIEncoding();
                    byte[] buffer = encoder.GetBytes(printQueue.Dequeue());
                    clientStream.Write(buffer, 0, buffer.Length);

                    // Se não tiver mais nada para imprimir, cai fora
                    if (!printQueue.Any()) break;
                }
                clientStream.Flush();
            }
        }
    }
}

Experiência do Usuário

Para melhorar a experiência do usuário, podemos implementar uma tela de espera, pois dependendo do volume de dados a impressão pode demorar.

Para implementar a tela de espera, dê uma olhada neste tópico:

1 curtida