Saltar al pie de página
USO DE IRONBARCODE

Escáner de código de barras USB en C#: Cree una aplicación de escaneo completa

Los lectores de códigos de barras USB se conectan a aplicaciones C# como dispositivos de entrada de teclado estándar y envían datos escaneados como caracteres escritos seguidos de una pulsación de tecla Intro. Este comportamiento de cuña de teclado HID hace que la integración sea sencilla: su aplicación recibe entrada de texto sin necesidad de ningún controlador o SDK especial. IronBarcode procesa esa entrada sin procesar para validar formatos, extraer datos estructurados y generar códigos de barras de respuesta, convirtiendo un simple evento de escaneo en una tubería de datos completa para la gestión de inventario, puntos de venta minoristas y sistemas de seguimiento logístico.

Las operaciones de venta minorista, almacenamiento y fabricación dependen de un escaneo rápido y preciso de códigos de barras. Cuando un desarrollador conecta un escáner USB a una aplicación de Windows Forms o WPF, el escáner se comporta de manera idéntica a un teclado: los datos llegan a un cuadro de texto y al presionar Enter se indica que se ha recibido un código de barras completo. El desafío no es capturar los datos; Lo está procesando correctamente. La validación de código de barras de IronBarcode verifica la integridad del formato, extrae campos como números de lote o identificadores de aplicaciones GS1 y puede generar inmediatamente un nuevo código de barras en respuesta.

Esta guía explica paso a paso la creación de una aplicación de escáner de códigos de barras USB en C# lista para producción. Instalará la biblioteca, capturará la entrada del escáner, validará los formatos de los códigos de barras, generará etiquetas de respuesta y ensamblará un procesador de colas de alto volumen. Cada sección incluye código completo y ejecutable orientado a .NET 10 con estilo de declaración de nivel superior cuando corresponda.

¿Cómo funcionan los escáneres de códigos de barras USB con C#?

¿Por qué el modo de cuña de teclado HID simplifica la integración?

La mayoría de los escáneres de códigos de barras USB se envían configurados en modo de cuña de teclado HID de manera predeterminada. Cuando lo conectas a una máquina Windows, el sistema operativo lo registra como un dispositivo de almacenamiento USB (para configuración) y como un teclado (para entrada de datos). Cuando se escanea un código de barras, el dispositivo traduce el valor del código de barras decodificado en pulsaciones de teclas y las envía a la ventana de la aplicación que tenga el foco, agregando un retorno de carro al final.

Desde la perspectiva de un desarrollador de C#, esto significa que no se necesitan SDK de proveedores, bibliotecas COM ni API USB especiales. Un TextBox estándar con un controlador KeyDown es todo lo que se necesita para capturar la entrada. El principal desafío de integración es distinguir la entrada del escáner de la escritura genuina en el teclado. Los escáneres generalmente entregan todos los caracteres en un lapso muy corto (a menudo menos de 50 milisegundos), mientras que la escritura humana distribuye las pulsaciones de teclas a lo largo de cientos de milisegundos. Medir el tiempo de la ráfaga es una forma confiable de filtrar pulsaciones de teclas accidentales.

Los escáneres de nivel profesional también admiten modos seriales (RS-232 o puerto COM virtual) y USB HID directo, que le brindan más control sobre los caracteres de prefijo/sufijo y los activadores de escaneo. El patrón de interfaz a continuación maneja ambos casos:

public interface IScannerInput
{
    event EventHandler<string> BarcodeScanned;
    void StartListening();
    void StopListening();
}

public class KeyboardWedgeScanner : IScannerInput
{
    public event EventHandler<string> BarcodeScanned;
    private readonly TextBox _inputBox;
    private readonly System.Windows.Forms.Timer _burstTimer;
    private readonly System.Text.StringBuilder _buffer = new();

    public KeyboardWedgeScanner(TextBox inputBox)
    {
        _inputBox = inputBox;
        _burstTimer = new System.Windows.Forms.Timer { Interval = 80 };
        _burstTimer.Tick += OnBurstTimeout;
        _inputBox.KeyPress += OnKeyPress;
    }

    private void OnKeyPress(object sender, KeyPressEventArgs e)
    {
        if (e.KeyChar == (char)Keys.Enter)
        {
            _burstTimer.Stop();
            string value = _buffer.ToString().Trim();
            _buffer.Clear();
            if (value.Length > 0)
                BarcodeScanned?.Invoke(this, value);
        }
        else
        {
            _buffer.Append(e.KeyChar);
            _burstTimer.Stop();
            _burstTimer.Start();
        }
        e.Handled = true;
    }

    private void OnBurstTimeout(object sender, EventArgs e)
    {
        _burstTimer.Stop();
        _buffer.Clear(); // incomplete burst -- discard
    }

    public void StartListening() => _inputBox.Focus();
    public void StopListening() => _inputBox.Enabled = false;
}

public class SerialPortScanner : IScannerInput
{
    public event EventHandler<string> BarcodeScanned;
    private readonly System.IO.Ports.SerialPort _port;

    public SerialPortScanner(string portName, int baudRate = 9600)
    {
        _port = new System.IO.Ports.SerialPort(portName, baudRate);
        _port.DataReceived += OnDataReceived;
    }

    private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        string data = _port.ReadLine().Trim();
        if (data.Length > 0)
            BarcodeScanned?.Invoke(this, data);
    }

    public void StartListening() => _port.Open();
    public void StopListening() => _port.Close();
}
public interface IScannerInput
{
    event EventHandler<string> BarcodeScanned;
    void StartListening();
    void StopListening();
}

public class KeyboardWedgeScanner : IScannerInput
{
    public event EventHandler<string> BarcodeScanned;
    private readonly TextBox _inputBox;
    private readonly System.Windows.Forms.Timer _burstTimer;
    private readonly System.Text.StringBuilder _buffer = new();

    public KeyboardWedgeScanner(TextBox inputBox)
    {
        _inputBox = inputBox;
        _burstTimer = new System.Windows.Forms.Timer { Interval = 80 };
        _burstTimer.Tick += OnBurstTimeout;
        _inputBox.KeyPress += OnKeyPress;
    }

    private void OnKeyPress(object sender, KeyPressEventArgs e)
    {
        if (e.KeyChar == (char)Keys.Enter)
        {
            _burstTimer.Stop();
            string value = _buffer.ToString().Trim();
            _buffer.Clear();
            if (value.Length > 0)
                BarcodeScanned?.Invoke(this, value);
        }
        else
        {
            _buffer.Append(e.KeyChar);
            _burstTimer.Stop();
            _burstTimer.Start();
        }
        e.Handled = true;
    }

    private void OnBurstTimeout(object sender, EventArgs e)
    {
        _burstTimer.Stop();
        _buffer.Clear(); // incomplete burst -- discard
    }

    public void StartListening() => _inputBox.Focus();
    public void StopListening() => _inputBox.Enabled = false;
}

public class SerialPortScanner : IScannerInput
{
    public event EventHandler<string> BarcodeScanned;
    private readonly System.IO.Ports.SerialPort _port;

    public SerialPortScanner(string portName, int baudRate = 9600)
    {
        _port = new System.IO.Ports.SerialPort(portName, baudRate);
        _port.DataReceived += OnDataReceived;
    }

    private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        string data = _port.ReadLine().Trim();
        if (data.Length > 0)
            BarcodeScanned?.Invoke(this, data);
    }

    public void StartListening() => _port.Open();
    public void StopListening() => _port.Close();
}
$vbLabelText   $csharpLabel

El temporizador de ráfaga en la implementación del teclado en cuña es el detalle clave. Se reinicia con cada pulsación de tecla y solo se activa si dejan de llegar caracteres, lo que significa que los usuarios de teclado genuinos que escriben lentamente verán su entrada incompleta descartada en lugar de ser tratada como un escaneo de código de barras.

¿Cómo gestionar múltiples marcas de escáneres?

Los entornos empresariales con frecuencia utilizan una combinación de escáneres Honeywell, Zebra (anteriormente Symbol/Motorola) y Datalogic en el mismo piso. Cada proveedor tiene sus propios caracteres de terminación predeterminados, velocidades en baudios y convenciones de prefijo/sufijo. Un modelo de configuración mantiene su aplicación flexible:

public class ScannerConfiguration
{
    public string ScannerType { get; set; } = "KeyboardWedge";
    public string PortName { get; set; } = "COM3";
    public int BaudRate { get; set; } = 9600;
    public string Terminator { get; set; } = "\r\n";
    public bool EnableBeep { get; set; } = true;
    public Dictionary<string, string> BrandSettings { get; set; } = new();

    public static ScannerConfiguration GetHoneywellConfig() => new()
    {
        ScannerType = "Serial",
        BaudRate = 115200,
        BrandSettings = new Dictionary<string, string>
        {
            { "Prefix", "STX" },
            { "Suffix", "ETX" },
            { "TriggerMode", "Manual" }
        }
    };

    public static ScannerConfiguration GetZebraConfig() => new()
    {
        ScannerType = "KeyboardWedge",
        BrandSettings = new Dictionary<string, string>
        {
            { "ScanMode", "Continuous" },
            { "BeepVolume", "High" }
        }
    };
}
public class ScannerConfiguration
{
    public string ScannerType { get; set; } = "KeyboardWedge";
    public string PortName { get; set; } = "COM3";
    public int BaudRate { get; set; } = 9600;
    public string Terminator { get; set; } = "\r\n";
    public bool EnableBeep { get; set; } = true;
    public Dictionary<string, string> BrandSettings { get; set; } = new();

    public static ScannerConfiguration GetHoneywellConfig() => new()
    {
        ScannerType = "Serial",
        BaudRate = 115200,
        BrandSettings = new Dictionary<string, string>
        {
            { "Prefix", "STX" },
            { "Suffix", "ETX" },
            { "TriggerMode", "Manual" }
        }
    };

    public static ScannerConfiguration GetZebraConfig() => new()
    {
        ScannerType = "KeyboardWedge",
        BrandSettings = new Dictionary<string, string>
        {
            { "ScanMode", "Continuous" },
            { "BeepVolume", "High" }
        }
    };
}
$vbLabelText   $csharpLabel

Almacenar estas configuraciones en un archivo de configuración o una base de datos significa que el personal del almacén puede cambiar los modelos de escáner sin necesidad de una redistribución. El campo ScannerType determina qué implementación de IScannerInput se instancia al inicio.

¿Cómo instalar IronBarcode en un proyecto C#?

¿Cuál es la forma más rápida de agregar IronBarcode a través de NuGet?

Abra la consola del gestor de paquetes en Visual Studio y ejecute:

Install-Package IronBarCode
Install-Package IronBarCode
SHELL

Alternativamente, utilice la CLI de .NET :

dotnet add package IronBarCode
dotnet add package IronBarCode
SHELL

Ambos comandos extraen la versión actual de NuGet y añaden la referencia del ensamblado al archivo de proyecto. La biblioteca está diseñada for .NET Standard 2.0, por lo que funciona en .NET Framework 4.6.2 a .NET 10 sin necesidad de correcciones de compatibilidad adicionales.

Después de la instalación, configure su clave de licencia antes de llamar a cualquier método IronBarcode . Para desarrollo y evaluación, hay una clave de prueba gratuita disponible en la página de licencias de IronBarcode :

IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
$vbLabelText   $csharpLabel

Para implementaciones en contenedores, IronBarcode funciona con Docker en Linux y, para funciones en la nube, es compatible con AWS Lambda y Azure Functions .

¿Cómo validar códigos de barras escaneados con IronBarcode?

¿Cuál es el enfoque correcto para la verificación de formato?

IronBarcode admite más de 30 simbologías de códigos de barras, incluidos Code 128 , EAN-13 , Code 39 , códigos QR y Data Matrix . Para las aplicaciones de escáner USB, el patrón de validación vuelve a codificar la cadena escaneada como una imagen de código de barras y la lee inmediatamente a través del decodificador. Este viaje de ida y vuelta confirma que la cadena es un valor válido para el formato declarado:

public class BarcodeValidator
{
    public async Task<ValidationResult> ValidateAsync(string scannedText, BarcodeEncoding preferredFormat = BarcodeEncoding.Code128)
    {
        var result = new ValidationResult { RawInput = scannedText };

        try
        {
            var barcode = BarcodeWriter.CreateBarcode(scannedText, preferredFormat);
            var readResults = await BarcodeReader.ReadAsync(barcode.ToBitmap());

            if (readResults.Any())
            {
                var first = readResults.First();
                result.IsValid = true;
                result.Format = first.BarcodeType;
                result.Value = first.Value;
                result.Confidence = first.Confidence;
            }
            else
            {
                result.IsValid = false;
                result.Error = "No barcode could be decoded from the scanned input.";
            }
        }
        catch (Exception ex)
        {
            result.IsValid = false;
            result.Error = ex.Message;
        }

        return result;
    }
}

public record ValidationResult
{
    public string RawInput { get; init; } = "";
    public bool IsValid { get; set; }
    public BarcodeEncoding Format { get; set; }
    public string Value { get; set; } = "";
    public float Confidence { get; set; }
    public string Error { get; set; } = "";
}
public class BarcodeValidator
{
    public async Task<ValidationResult> ValidateAsync(string scannedText, BarcodeEncoding preferredFormat = BarcodeEncoding.Code128)
    {
        var result = new ValidationResult { RawInput = scannedText };

        try
        {
            var barcode = BarcodeWriter.CreateBarcode(scannedText, preferredFormat);
            var readResults = await BarcodeReader.ReadAsync(barcode.ToBitmap());

            if (readResults.Any())
            {
                var first = readResults.First();
                result.IsValid = true;
                result.Format = first.BarcodeType;
                result.Value = first.Value;
                result.Confidence = first.Confidence;
            }
            else
            {
                result.IsValid = false;
                result.Error = "No barcode could be decoded from the scanned input.";
            }
        }
        catch (Exception ex)
        {
            result.IsValid = false;
            result.Error = ex.Message;
        }

        return result;
    }
}

public record ValidationResult
{
    public string RawInput { get; init; } = "";
    public bool IsValid { get; set; }
    public BarcodeEncoding Format { get; set; }
    public string Value { get; set; } = "";
    public float Confidence { get; set; }
    public string Error { get; set; } = "";
}
$vbLabelText   $csharpLabel

Para los códigos de barras GS1-128 utilizados en aplicaciones de la cadena de suministro, la cadena escaneada incluye prefijos de identificador de aplicación entre paréntesis, como (01) para GTIN y (17) para fecha de vencimiento. IronBarcode analiza estos identificadores de aplicación automáticamente cuando usted especifica BarcodeEncoding.GS1_128.

¿Qué lógica de suma de comprobación EAN-13 deberían implementar los desarrolladores?

Las aplicaciones de punto de venta minorista suelen necesitar verificar los dígitos de control EAN-13 de forma independiente antes de pasar el valor a una consulta de precios. La suma de comprobación estilo Luhn para EAN-13 alterna pesos de 1 y 3 en los primeros 12 dígitos:

public static bool ValidateEan13Checksum(string value)
{
    if (value.Length != 13 || !value.All(char.IsDigit))
        return false;

    int sum = 0;
    for (int i = 0; i < 12; i++)
    {
        int digit = value[i] - '0';
        sum += (i % 2 == 0) ? digit : digit * 3;
    }

    int expectedCheck = (10 - (sum % 10)) % 10;
    return expectedCheck == (value[12] - '0');
}
public static bool ValidateEan13Checksum(string value)
{
    if (value.Length != 13 || !value.All(char.IsDigit))
        return false;

    int sum = 0;
    for (int i = 0; i < 12; i++)
    {
        int digit = value[i] - '0';
        sum += (i % 2 == 0) ? digit : digit * 3;
    }

    int expectedCheck = (10 - (sum % 10)) % 10;
    return expectedCheck == (value[12] - '0');
}
$vbLabelText   $csharpLabel

Esta verificación de lógica pura se ejecuta antes de la codificación para evitar la sobrecarga de la generación de imágenes de ida y vuelta para cada escaneo en un entorno minorista de gran volumen. Según la especificación GS1 , el algoritmo del dígito de verificación es idéntico para UPC-A (12 dígitos) cuando se elimina el cero inicial.

¿Cómo generar códigos de barras de respuesta a partir de una entrada escaneada?

¿Cuándo debe una aplicación crear nuevos códigos de barras después de un escaneo?

Un patrón común en la recepción en el almacén es el flujo de trabajo de "escanear y volver a etiquetar": un artículo entrante lleva un código de barras de proveedor (a menudo EAN-13 o ITF-14), y el sistema de gestión del almacén necesita imprimir una etiqueta interna Código 128 con su propia ubicación y códigos de lote. Las capacidades de generación de IronBarcode manejan esto en unas pocas líneas:

public class InventoryLabelGenerator
{
    private readonly string _outputDirectory;

    public InventoryLabelGenerator(string outputDirectory)
    {
        _outputDirectory = outputDirectory;
        Directory.CreateDirectory(_outputDirectory);
    }

    public async Task<string> GenerateLabelAsync(string internalCode, string locationCode)
    {
        string fullCode = $"{internalCode}|{locationCode}|{DateTime.UtcNow:yyyyMMdd}";

        // Primary Code 128 label for scanners
        var linearBarcode = BarcodeWriter.CreateBarcode(fullCode, BarcodeEncoding.Code128);
        linearBarcode.ResizeTo(500, 140);
        linearBarcode.SetMargins(12);
        linearBarcode.AddAnnotationTextAboveBarcode(fullCode);
        linearBarcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Black);

        // QR code companion for mobile apps
        var qrCode = BarcodeWriter.CreateQrCode(fullCode);
        qrCode.ResizeTo(200, 200);
        qrCode.SetMargins(8);

        string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
        string pngPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.png");
        string pdfPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.pdf");

        await Task.Run(() =>
        {
            linearBarcode.SaveAsPng(pngPath);
            linearBarcode.SaveAsPdf(pdfPath);
        });

        return pngPath;
    }
}
public class InventoryLabelGenerator
{
    private readonly string _outputDirectory;

    public InventoryLabelGenerator(string outputDirectory)
    {
        _outputDirectory = outputDirectory;
        Directory.CreateDirectory(_outputDirectory);
    }

    public async Task<string> GenerateLabelAsync(string internalCode, string locationCode)
    {
        string fullCode = $"{internalCode}|{locationCode}|{DateTime.UtcNow:yyyyMMdd}";

        // Primary Code 128 label for scanners
        var linearBarcode = BarcodeWriter.CreateBarcode(fullCode, BarcodeEncoding.Code128);
        linearBarcode.ResizeTo(500, 140);
        linearBarcode.SetMargins(12);
        linearBarcode.AddAnnotationTextAboveBarcode(fullCode);
        linearBarcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Black);

        // QR code companion for mobile apps
        var qrCode = BarcodeWriter.CreateQrCode(fullCode);
        qrCode.ResizeTo(200, 200);
        qrCode.SetMargins(8);

        string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
        string pngPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.png");
        string pdfPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.pdf");

        await Task.Run(() =>
        {
            linearBarcode.SaveAsPng(pngPath);
            linearBarcode.SaveAsPdf(pdfPath);
        });

        return pngPath;
    }
}
$vbLabelText   $csharpLabel

Guardar como PDF es especialmente útil para impresoras de etiquetas que aceptan la entrada de PDF a través de un recurso compartido de red. También puede exportar como SVG para obtener una salida de etiqueta térmica con calidad vectorial, o exportar como un flujo de bytes para enviar directamente a una API de impresora de etiquetas.

IronBarcode admite una amplia personalización de estilo que incluye colores personalizados, ajustes de márgenes , superposiciones de texto legible por humanos y, para códigos QR, incrustación de logotipos para etiquetas móviles con la marca marcada.

![Interfaz de la aplicación Windows Forms que demuestra las capacidades de generación dual de códigos de barras de IronBarcode. La interfaz muestra la generación exitosa de un código de barras lineal Código 128 y un código QR para el número de inventario 'INV-20250917-helloworld'. El campo de entrada en la parte superior permite a los usuarios ingresar códigos de inventario personalizados, con un botón "Generar" para crear los códigos de barras. El mensaje de éxito 'Artículo procesado exitosamente - Etiquetas generadas' confirma que la operación se completó. El código de barras Code 128 se considera el formato principal para el seguimiento de inventario, mientras que el código QR a continuación se considera una alternativa optimizada para dispositivos móviles. La aplicación utiliza un fondo gris profesional con una jerarquía visual clara, lo que demuestra cómo IronBarcode permite a los desarrolladores crear sistemas de generación de códigos de barras multiformato para una gestión completa del inventario.

¿Cómo crear una aplicación completa de escaneo de alto volumen?

¿Cómo es una implementación basada en una cola de producción?

Para las aplicaciones que procesan docenas de escaneos por minuto, un simple controlador sincrónico en el hilo de UI se convierte en un cuello de botella. El siguiente patrón desacopla la captura de escaneo del procesamiento mediante un bucle ConcurrentQueue<t> y un procesamiento en segundo plano. La API asíncrona de IronBarcode gestiona la validación sin bloquear la interfaz de usuario:

using IronBarCode;
using System.Collections.Concurrent;

public partial class HighVolumeScanner : Form
{
    private readonly ConcurrentQueue<(string Data, DateTime Timestamp)> _scanQueue = new();
    private readonly SemaphoreSlim _semaphore;
    private readonly CancellationTokenSource _cts = new();
    private IScannerInput _scanner;

    public HighVolumeScanner()
    {
        InitializeComponent();
        IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
        _semaphore = new SemaphoreSlim(Environment.ProcessorCount);
        InitializeScanner();
        _ = RunProcessingLoopAsync();
    }

    private void InitializeScanner()
    {
        _scanner = System.IO.Ports.SerialPort.GetPortNames().Any()
            ? new SerialPortScanner("COM3", 115200)
            : new KeyboardWedgeScanner(txtScannerInput);

        _scanner.BarcodeScanned += (_, barcode) =>
            _scanQueue.Enqueue((barcode, DateTime.UtcNow));

        _scanner.StartListening();
    }

    private async Task RunProcessingLoopAsync()
    {
        while (!_cts.Token.IsCancellationRequested)
        {
            if (_scanQueue.TryDequeue(out var scan))
            {
                await _semaphore.WaitAsync(_cts.Token);
                _ = Task.Run(async () =>
                {
                    try { await ProcessScanAsync(scan.Data, scan.Timestamp); }
                    finally { _semaphore.Release(); }
                }, _cts.Token);
            }
            else
            {
                await Task.Delay(10, _cts.Token);
            }
        }
    }

    private async Task ProcessScanAsync(string rawData, DateTime scanTime)
    {
        var options = new BarcodeReaderOptions
        {
            Speed = ReadingSpeed.Equilibrado,
            ExpectMultipleBarcodes = false,
            ExpectBarcodeTypes = BarcodeEncoding.Code128 | BarcodeEncoding.QRCode,
            MaxParallelThreads = 1
        };

        var testBarcode = BarcodeWriter.CreateBarcode(rawData, BarcodeEncoding.Code128);
        var results = await BarcodeReader.ReadAsync(testBarcode.ToBitmap(), options);

        if (results.Any())
        {
            var item = results.First();
            BeginInvoke(() => UpdateInventoryDisplay(item.Value, scanTime));
        }
        else
        {
            BeginInvoke(() => LogRejectedScan(rawData, scanTime));
        }
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        _cts.Cancel();
        _scanner.StopListening();
        base.OnFormClosing(e);
    }
}
using IronBarCode;
using System.Collections.Concurrent;

public partial class HighVolumeScanner : Form
{
    private readonly ConcurrentQueue<(string Data, DateTime Timestamp)> _scanQueue = new();
    private readonly SemaphoreSlim _semaphore;
    private readonly CancellationTokenSource _cts = new();
    private IScannerInput _scanner;

    public HighVolumeScanner()
    {
        InitializeComponent();
        IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
        _semaphore = new SemaphoreSlim(Environment.ProcessorCount);
        InitializeScanner();
        _ = RunProcessingLoopAsync();
    }

    private void InitializeScanner()
    {
        _scanner = System.IO.Ports.SerialPort.GetPortNames().Any()
            ? new SerialPortScanner("COM3", 115200)
            : new KeyboardWedgeScanner(txtScannerInput);

        _scanner.BarcodeScanned += (_, barcode) =>
            _scanQueue.Enqueue((barcode, DateTime.UtcNow));

        _scanner.StartListening();
    }

    private async Task RunProcessingLoopAsync()
    {
        while (!_cts.Token.IsCancellationRequested)
        {
            if (_scanQueue.TryDequeue(out var scan))
            {
                await _semaphore.WaitAsync(_cts.Token);
                _ = Task.Run(async () =>
                {
                    try { await ProcessScanAsync(scan.Data, scan.Timestamp); }
                    finally { _semaphore.Release(); }
                }, _cts.Token);
            }
            else
            {
                await Task.Delay(10, _cts.Token);
            }
        }
    }

    private async Task ProcessScanAsync(string rawData, DateTime scanTime)
    {
        var options = new BarcodeReaderOptions
        {
            Speed = ReadingSpeed.Equilibrado,
            ExpectMultipleBarcodes = false,
            ExpectBarcodeTypes = BarcodeEncoding.Code128 | BarcodeEncoding.QRCode,
            MaxParallelThreads = 1
        };

        var testBarcode = BarcodeWriter.CreateBarcode(rawData, BarcodeEncoding.Code128);
        var results = await BarcodeReader.ReadAsync(testBarcode.ToBitmap(), options);

        if (results.Any())
        {
            var item = results.First();
            BeginInvoke(() => UpdateInventoryDisplay(item.Value, scanTime));
        }
        else
        {
            BeginInvoke(() => LogRejectedScan(rawData, scanTime));
        }
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        _cts.Cancel();
        _scanner.StopListening();
        base.OnFormClosing(e);
    }
}
$vbLabelText   $csharpLabel

El SemaphoreSlim limita las tareas de validación simultáneas a la cantidad de procesadores lógicos, lo que evita la creación de subprocesos descontrolados durante eventos de escaneo en ráfaga. El BeginInvoke llama a las actualizaciones de la interfaz de usuario de Marshal y las devuelve al hilo principal de forma segura.

¿Cómo ajustar el rendimiento para diferentes volúmenes de escaneo?

La propiedad BarcodeReaderOptions.Speed acepta ReadingSpeed.Más rápido, ReadingSpeed.Equilibrado y ReadingSpeed.Detallado. Para la entrada del escáner USB donde ya se conoce el valor de la cadena, Equilibrado es apropiado: el decodificador solo necesita confirmar el formato, no ubicar un código de barras en una imagen. Según la documentación de velocidad de lectura de IronBarcode , el modo Más rápido omite algunos algoritmos de corrección de distorsión, lo que es seguro para una salida de escáner limpia, pero puede no detectar códigos de barras dañados en escenarios basados ​​en imágenes.

La siguiente tabla resume cuándo utilizar cada modo de velocidad:

Modos de velocidad de lectura de IronBarcode y sus casos de uso apropiados
Modo de velocidad Mejor para Compensación
Más rápido Entrada de escáner USB limpia, alto rendimiento Es posible que no se detecten códigos de barras muy dañados o torcidos
Equilibrado Entrada mixta: escáner USB más importación de imágenes Uso moderado de CPU, buena precisión.
Detallado Etiquetas dañadas, impresión de bajo contraste, importaciones de PDF Mayor uso de CPU, rendimiento más lento

Para las aplicaciones que también procesan imágenes o archivos PDF junto con la entrada del escáner USB, IronBarcode puede leer códigos de barras de documentos PDF y archivos TIFF de varias páginas utilizando la misma superficie API.

Aplicación de escáner de código de barras de Windows Forms profesional que muestra las capacidades de seguimiento de inventario en tiempo real de IronBarcode. La interfaz presenta un diseño limpio de dos paneles con un sofisticado encabezado azul oscuro. El panel izquierdo muestra una lista del historial de escaneo que muestra cuatro elementos de inventario escaneados exitosamente (INV-001 a INV-004) con marcas de tiempo precisas e indicadores de estado de escaneo. Cada artículo incluye metadatos detallados como el tipo de código de barras y el nivel de confianza. El panel derecho muestra un código de barras de resumen generado dinámicamente que muestra 'Elementos: 4' con un estilo profesional y márgenes adecuados. Los botones de acción en la parte inferior incluyen 'Borrar lista', 'Exportar datos' e 'Imprimir etiquetas' para una gestión completa del inventario. La barra de estado indica 'Escáner: Conectado | Modo: Continuo | 'Último escaneo: hace 2 segundos', que demuestra las capacidades de monitoreo en tiempo real de la aplicación y el diseño profesional listo para la empresa que IronBarcode permite para los sistemas de inventario de producción.

¿Cómo manejar casos extremos y errores en aplicaciones de escáner?

¿Qué modos de fallo deberían anticipar los desarrolladores?

Las aplicaciones de escáner USB fallan de manera predecible. Los problemas más comunes y sus mitigaciones son:

Desconexión del escáner : cuando se desconecta un escáner USB, el teclado TextBox pierde su teclado virtual. La mitigación más simple es un temporizador periódico que verifica _inputBox.Focused y lo vuelve a enfocar si el escáner todavía aparece en los dispositivos HID conectados. Para los escáneres en serie, SerialPort.GetPortNames() detecta la reconexión.

Formatos de códigos de barras ambiguos : algunos productos llevan códigos de barras que son válidos en múltiples simbologías. Por ejemplo, una cadena de 12 dígitos es un UPC-A válido y también un Código 128 válido. Especificar ExpectBarcodeTypes en BarcodeReaderOptions restringe el decodificador a los formatos esperados y elimina la ambigüedad. La guía de solución de problemas de IronBarcode cubre consejos de reconocimiento específicos del formato.

Excepciones de formato no válido : si BarcodeWriter.CreateBarcode recibe una cadena que viola las reglas de codificación seleccionada (por ejemplo, caracteres alfabéticos en un campo EAN-13 solo numérico), genera un IronBarCode.Exceptions.InvalidBarcodeException. Envolver la llamada en un try-catch y volver a una ruta de validación de solo cadena mantiene la aplicación en ejecución.

Colisiones de tiempos de pulsaciones de teclas : en entornos donde los operadores también escriben manualmente en el mismo cuadro de texto, el enfoque del temporizador de ráfaga descrito anteriormente es la defensa principal. Una protección secundaria es la longitud mínima: la mayoría de los códigos de barras reales tienen al menos 8 caracteres, por lo que las cadenas más cortas pueden tratarse como entrada de teclado.

La documentación de Microsoft .NET sobre System.IO.Ports.SerialPort es útil para solucionar problemas de conectividad del escáner en serie, particularmente en torno a las configuraciones ReadTimeout y WriteTimeout. Para el cumplimiento normativo en el comercio minorista, las Especificaciones Generales GS1 definen rangos de valores válidos para cada identificador de aplicación.

¿Cómo ampliar la aplicación a plataformas móviles y web?

El patrón de interfaz del escáner que se muestra arriba -- IScannerInput con evento BarcodeScanned -- abstrae el hardware de la lógica de procesamiento. El intercambio de implementaciones permite que el mismo código de validación y generación se ejecute en diferentes plataformas:

  • .NET MAUI proporciona una implementación de escáner basada en cámara para tabletas Android e iOS utilizadas como estaciones receptoras móviles
  • Blazor Server admite el escaneo basado en navegador con acceso a la cámara JavaScript que alimenta el mismo evento BarcodeScanned
  • Las implementaciones nativas de Android e iOS brindan a los desarrolladores móviles la capacidad de escanear la cámara con el mismo decodificador IronBarcode en el backend.

Para las arquitecturas nativas de la nube, los pasos de validación y generación de etiquetas se pueden ejecutar como funciones de Azure activadas por mensajes de cola, y la aplicación de escritorio actúa solo como puerta de enlace de entrada del escáner. Esta separación es particularmente útil cuando la lógica de impresión de etiquetas debe centralizarse para la auditoría de cumplimiento.

¿Cuales son tus próximos pasos?

La creación de una aplicación de escáner de código de barras USB con IronBarcode implica cuatro etapas concretas: capturar la entrada del teclado con detección de ráfagas de tiempo, validar el valor escaneado a través del decodificador de IronBarcode, generar etiquetas de respuesta en el formato requerido y procesar grandes volúmenes de escaneo con una cola simultánea. Cada etapa es independiente y se puede probar de forma aislada.

Desde aquí, considere ampliar la aplicación con lectura de múltiples códigos de barras para escenarios de procesamiento por lotes, optimización de la región de cultivo para entradas basadas en imágenes o compatibilidad con códigos de barras MSI para equipos de almacén más antiguos. La documentación de IronBarcode cubre todos los formatos compatibles y las opciones avanzadas de configuración del lector.

Comience una prueba gratuita para obtener una clave de licencia de desarrollo y comience a integrar IronBarcode en su aplicación de escaneo hoy mismo.

Preguntas Frecuentes

¿Qué es IronBarcode y cómo se relaciona con los escáneres de código de barras USB?

IronBarcode es una biblioteca que permite a los desarrolladores construir aplicaciones robustas de C# para escaneo de códigos de barras USB. Ofrece funciones como validación de códigos de barras, extracción de datos y generación de códigos de barras.

¿Puede IronBarcode validar datos de código de barras de un escáner USB?

Sí, IronBarcode puede validar datos de códigos de barras capturados desde un escáner USB, asegurando la integridad y precisión de los datos en tus aplicaciones C#.

¿Cómo maneja IronBarcode la generación de códigos de barras?

IronBarcode puede generar nuevos códigos de barras al instante, permitiendo a los desarrolladores crear e imprimir códigos de barras fácilmente dentro de sus aplicaciones C#.

¿Existe soporte para manejo de errores en IronBarcode para el escaneo de códigos de barras USB?

Sí, IronBarcode incluye un manejo de errores completo para gestionar problemas comunes que pueden surgir durante la escaneo y proceso de códigos de barras USB.

¿Qué tipos de códigos de barras se pueden escanear con IronBarcode?

IronBarcode admite el escaneo de una amplia gama de simbologías de códigos de barras, incluyendo códigos QR, UPC, Código 39 y más, lo que lo hace versátil para diversas aplicaciones.

¿Puede IronBarcode extraer información estructurada de los códigos de barras escaneados?

Sí, IronBarcode puede extraer información estructurada de los códigos de barras escaneados, ayudando en el procesamiento y gestión eficiente de datos.

¿Cómo puedo comenzar a construir una aplicación de escáner de código de barras USB en C#?

Para comenzar a construir una aplicación de escáner de código de barras USB en C#, puedes utilizar IronBarcode junto con los ejemplos de código y la documentación proporcionada para guiar tu proceso de desarrollo.

Jordi Bardia
Ingeniero de Software
Jordi es más competente en Python, C# y C++. Cuando no está aprovechando sus habilidades en Iron Software, está programando juegos. Compartiendo responsabilidades para pruebas de productos, desarrollo de productos e investigación, Jordi agrega un valor inmenso a la mejora continua del producto. La experiencia variada lo mantiene ...
Leer más

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame