Passer au contenu du pied de page
UTILISATION DE IRONBARCODE

Scanner de codes-barres USB en C# : Créez une application de numérisation complète

Les lecteurs de codes-barres USB se connectent aux applications C# comme des périphériques d'entrée clavier standard, envoyant les données scannées sous forme de caractères saisis suivis d'une pression sur la touche Entrée. Ce comportement de ce clavier HID simplifie l'intégration : votre application reçoit les entrées de texte sans qu'aucun pilote ou SDK spécial ne soit requis. IronBarcode traite ces données brutes pour valider les formats, extraire les données structurées et générer des codes-barres de réponse, transformant ainsi un simple événement de numérisation en un pipeline de données complet pour la gestion des stocks, les points de vente au détail et les systèmes de suivi logistique.

Les activités de vente au détail, d'entreposage et de fabrication dépendent toutes d'une lecture rapide et précise des codes-barres. Lorsqu'un développeur connecte un scanner USB à une application Windows Forms ou WPF, le scanner se comporte de la même manière qu'un clavier : les données arrivent dans une zone de texte, et appuyer sur Entrée signale qu'un code-barres complet a été reçu. Le défi n'est pas de recueillir les données ; Le traitement se déroule correctement. Le système de validation de codes-barres d'IronBarcode vérifie l'intégrité du format, extrait des champs tels que les numéros de lot ou les identifiants d'application GS1 et peut générer immédiatement un nouveau code-barres en réponse.

Ce guide vous accompagne pas à pas dans la création d'une application de lecture de codes-barres USB en C# prête pour la production. Vous installerez la bibliothèque, capturerez les données du scanner, validerez les formats de codes-barres, générerez les étiquettes de réponse et assemblerez un processeur à file d'attente pour un volume élevé de données. Chaque section comprend un code complet et exécutable ciblant .NET 10 avec un style d'instruction de niveau supérieur lorsque cela est approprié.

Comment fonctionnent les lecteurs de codes-barres USB avec C# ?

Pourquoi le mode Wedge du clavier HID simplifie-t-il l'intégration ?

La plupart des lecteurs de codes-barres USB sont livrés configurés par défaut en mode clavier HID. Lorsque vous branchez un tel appareil sur un ordinateur Windows, le système d'exploitation l'enregistre à la fois comme un périphérique de stockage USB (pour la configuration) et comme un clavier (pour la saisie de données). Lorsqu'un code-barres est scanné, l'appareil traduit la valeur décodée du code-barres en frappes de clavier et les envoie à la fenêtre d'application qui a le focus, en ajoutant un retour chariot à la fin.

Du point de vue d'un développeur C#, cela signifie qu'il n'est pas nécessaire d'utiliser les kits de développement logiciel (SDK) des fournisseurs, les bibliothèques COM ou les API USB spécifiques. Un simple contrôle TextBox avec un gestionnaire d'événement KeyDown suffit pour la saisie. Le principal défi d'intégration consiste à distinguer les données saisies par scanner de la véritable saisie au clavier. Les scanners délivrent généralement tous les caractères en un laps de temps très court — souvent moins de 50 millisecondes — tandis que la frappe humaine répartit les frappes sur des centaines de millisecondes. Le déclenchement temporel de la rafale est un moyen fiable de filtrer les frappes accidentelles.

Les scanners de qualité professionnelle prennent également en charge les modes série (RS-232 ou port COM virtuel) et USB HID direct, ce qui vous offre un meilleur contrôle sur les caractères de préfixe/suffixe et les déclencheurs de numérisation. Le modèle d'interface ci-dessous gère les deux cas :

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

Le minuteur de rafale intégré au clavier est un détail essentiel. Il se réinitialise à chaque frappe et ne se déclenche que si aucun caractère n'est enregistré, ce qui signifie que les utilisateurs de clavier qui tapent lentement verront leurs saisies incomplètes rejetées plutôt que traitées comme un scan de code-barres.

Comment gérez-vous plusieurs marques de scanners ?

Dans les environnements Enterprise , on trouve fréquemment un mélange de scanners Honeywell, Zebra (anciennement Symbol/Motorola) et Datalogic sur le même étage. Chaque fournisseur possède ses propres caractères de terminaison par défaut, ses débits de transmission et ses conventions de préfixe/suffixe. Un modèle de configuration assure la flexibilité de votre application :

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

Le stockage de ces configurations dans un fichier de paramètres ou une base de données permet au personnel de l'entrepôt de changer de modèle de scanner sans nécessiter de redéploiement. Le champ ScannerType détermine quelle implémentation IScannerInput est instanciée au démarrage.

Comment installer IronBarcode dans un projet C# ?

Quelle est la méthode la plus rapide pour ajouter IronBarcode via NuGet?

Ouvrez la console du Package Manager dans Visual Studio et exécutez :

Install-Package IronBarCode
Install-Package IronBarCode
SHELL

Vous pouvez également utiliser l'interface de ligne de commande .NET :

dotnet add package IronBarCode
dotnet add package IronBarCode
SHELL

Ces deux commandes téléchargent la version actuelle depuis NuGet et ajoutent la référence d'assembly à votre fichier projet. La bibliothèque cible .NET Standard 2.0 et fonctionne donc avec .NET Framework 4.6.2 à .NET 10 sans aucun module de compatibilité supplémentaire.

Après l'installation, définissez votre clé de licence avant d'appeler une méthode IronBarcode . Pour le développement et l'évaluation, une clé d'essai gratuite est disponible sur la page de licences IronBarcode :

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

Pour les déploiements conteneurisés, IronBarcode fonctionne avec Docker sous Linux , et pour les fonctions cloud, il prend en charge AWS Lambda et Azure Functions .

Comment valider les codes-barres scannés avec IronBarcode?

Quelle est la bonne approche pour la vérification du format ?

IronBarcode prend en charge plus de 30 symbologies de codes-barres, notamment Code 128 , EAN-13 , Code 39 , les codes QR et Data Matrix . Pour les applications de scanner USB, le modèle de validation réencode la chaîne scannée sous forme d'image de code-barres et la relit immédiatement via le décodeur. Cet aller-retour confirme que la chaîne est une valeur valide pour le format déclaré :

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

Pour les codes-barres GS1-128 utilisés dans les applications de la chaîne d'approvisionnement, la chaîne scannée comprend des préfixes d'identifiant d'application entre parenthèses tels que (01) pour le GTIN et (17) pour la date d'expiration. IronBarcode analyse automatiquement ces identifiants d'application lorsque vous spécifiez BarcodeEncoding.GS1_128.

Quelle logique de somme de contrôle EAN-13 les développeurs doivent-ils implémenter ?

Les applications de point de vente doivent souvent vérifier indépendamment les chiffres de contrôle EAN-13 avant de transmettre la valeur à une base de données de prix. La somme de contrôle de type Luhn pour EAN-13 alterne les valeurs 1 et 3 sur les 12 premiers chiffres :

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

Ce contrôle purement logique s'exécute avant l'encodage afin d'éviter la surcharge liée à la génération d'images aller-retour pour chaque scan dans un environnement de vente au détail à volume élevé. Selon la spécification GS1 , l'algorithme de chiffre de contrôle est identique pour UPC-A (12 chiffres) lorsque vous supprimez le zéro initial.

Comment générer des codes-barres de réponse à partir de données scannées ?

Quand une application doit-elle créer de nouveaux codes-barres après une numérisation ?

Un schéma courant dans la réception en entrepôt est le flux de travail " scan et réétiquetage " : un article entrant porte un code-barres fournisseur (souvent EAN-13 ou ITF-14), et le système de gestion d'entrepôt doit imprimer une étiquette interne Code 128 avec ses propres codes d'emplacement et de lot. Les fonctionnalités de génération d'IronBarcode gèrent cela en quelques lignes :

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

L'enregistrement au format PDF est particulièrement utile pour les imprimantes d'étiquettes qui acceptent les fichiers PDF en entrée via un partage réseau. Vous pouvez également exporter au format SVG pour obtenir des étiquettes thermiques vectorielles de haute qualité, ou exporter sous forme de flux d'octets pour l'envoyer directement à une API d'imprimante d'étiquettes.

IronBarcode prend en charge une personnalisation de style étendue, notamment les couleurs personnalisées, les ajustements de marge , les superpositions de texte lisibles par l'homme et, pour les codes QR, l'intégration de logos pour les étiquettes mobiles marquées de la marque.

Interface d'application Windows Forms démontrant les capacités de génération de codes-barres doubles d'IronBarcode. L'interface affiche la génération réussie d'un code-barres linéaire Code 128 et d'un code QR pour le numéro d'inventaire 'INV-20250917-helloworld'. Le champ de saisie situé en haut permet aux utilisateurs de saisir des codes d'inventaire personnalisés, avec un bouton  Générer  pour créer les codes-barres. Le message de succès  Article traité avec succès - Étiquettes générées  confirme que l'opération est terminée. Le code-barres Code 128 est désigné comme le format principal de suivi des stocks, tandis que le code QR ci-dessous est présenté comme une alternative adaptée aux appareils mobiles. L'application utilise un fond gris Professional avec une hiérarchie visuelle claire, démontrant comment IronBarcode permet aux développeurs de créer des systèmes de génération de codes-barres multiformats pour une gestion complète des stocks.

Comment créer une application de numérisation à haut volume complète ?

À quoi ressemble une implémentation de production basée sur une file d'attente ?

Pour les applications qui traitent des dizaines d'analyses par minute, un simple gestionnaire synchrone sur le thread d'interface utilisateur devient un goulot d'étranglement. Le modèle ci-dessous dissocie la capture du scan du traitement à l'aide d'un ConcurrentQueue<t> et d'une boucle de traitement en arrière-plan. L'API asynchrone d'IronBarcode gère la validation sans bloquer l'interface utilisateur :

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.Balanced,
            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.Balanced,
            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

Le SemaphoreSlim limite les tâches de validation simultanées au nombre de processeurs logiques, empêchant la création de threads incontrôlés lors d'événements de balayage en rafale. L'appel BeginInvoke renvoie les mises à jour de l'interface utilisateur au thread principal en toute sécurité.

Comment optimiser les performances pour différents volumes de numérisation ?

La propriété BarcodeReaderOptions.Speed accepte ReadingSpeed.Faster, ReadingSpeed.Balanced et ReadingSpeed.Detailed. Pour l'entrée du scanner USB où la valeur de la chaîne est déjà connue, Balanced est approprié -- le décodeur n'a besoin que de confirmer le format, pas de localiser un code-barres dans une image. Selon la documentation sur la vitesse de lecture d'IronBarcode , le mode Faster ignore certains algorithmes de correction de distorsion, ce qui est sûr pour une sortie de scanner propre mais peut manquer des codes-barres endommagés dans les scénarios basés sur l'image.

Le tableau suivant récapitule quand utiliser chaque mode de vitesse :

Modes de vitesse de lecture des IronBarcode et leurs cas d'utilisation appropriés
Mode vitesse Idéal pour Compromis
Plus rapide Entrée de scanner USB propre, débit élevé Peut ne pas détecter les codes-barres fortement endommagés ou déformés.
Équilibré Entrée mixte -- Scanner USB et importation d'images Utilisation modérée du processeur, bonne précision
Détaillé Étiquettes endommagées, impression à faible contraste, importations de PDF Utilisation du processeur plus élevée, débit le plus faible

Pour les applications qui traitent également des images ou des PDF en plus de l'entrée d'un scanner USB, IronBarcode peut lire les codes-barres des documents PDF et des fichiers TIFF multipages en utilisant la même interface API.

 Application Professional de lecture de codes-barres Windows Forms présentant les capacités de suivi d'inventaire en temps réel d'IronBarcode. L'interface présente un design épuré à deux panneaux avec un en-tête bleu foncé sophistiqué. Le panneau de gauche affiche une liste d'historique de numérisation montrant quatre articles d'inventaire numérisés avec succès (INV-001 à INV-004) avec des horodatages précis et des indicateurs d'état de numérisation. Chaque article comprend des métadonnées détaillées telles que le type de code-barres et le niveau de confiance. Le panneau de droite affiche un code-barres récapitulatif généré dynamiquement indiquant  Articles : 4  avec un style Professional et des marges appropriées. Les boutons d'action situés en bas comprennent  Effacer la liste ,  Exporter les données  et  Imprimer les étiquettes  pour une gestion complète des stocks. La barre d'état indique  Scanner : Connecté  | Mode : Continu | Dernière analyse : il y a 2 secondes , démontrant les capacités de surveillance en temps réel de l'application et sa conception Professional adaptée aux entreprises, IronBarcode permet pour les systèmes d'inventaire de production.

Comment gérez-vous les cas particuliers et les erreurs dans les applications de numérisation ?

Quels modes de défaillance les développeurs doivent-ils anticiper ?

Les applications de numérisation USB présentent des défaillances prévisibles. Les problèmes les plus courants et leurs solutions sont les suivants :

Déconnexion du scanner -- Lorsqu'un scanner USB est débranché, le contrôle TextBox perd son clavier virtuel. La solution la plus simple consiste en une minuterie périodique qui vérifie _inputBox.Focused et la recentre si le scanner est toujours répertorié dans les périphériques HID connectés. Pour les scanners série, SerialPort.GetPortNames() détecte la reconnexion.

Formats de codes-barres ambigus -- Certains produits portent des codes-barres valides dans plusieurs symbologies. Par exemple, une chaîne de 12 chiffres est un code UPC-A valide et également un code 128 valide. Spécifier ExpectBarcodeTypes dans BarcodeReaderOptions contraint le décodeur à vos formats attendus et élimine toute ambiguïté. Le guide de dépannage IronBarcode contient des conseils de reconnaissance spécifiques au format.

Exceptions de format non valide -- Si BarcodeWriter.CreateBarcode reçoit une chaîne qui enfreint les règles d'encodage sélectionnées (par exemple, des caractères alphabétiques dans un champ EAN-13 uniquement numérique), il génère une exception IronBarCode.Exceptions.InvalidBarcodeException. Envelopper l'appel dans un bloc try-catch et recourir à une validation basée uniquement sur les chaînes de caractères permet à l'application de continuer à fonctionner.

Collisions de synchronisation des frappes au clavier -- Dans les environnements où les opérateurs saisissent également manuellement du texte dans la même zone de texte, l'approche du minuteur en rafale décrite précédemment constitue la principale défense. Une protection secondaire concerne la longueur minimale : la plupart des codes-barres réels comportent au moins 8 caractères, donc les chaînes plus courtes peuvent être traitées comme une entrée clavier.

La documentation Microsoft .NET sur System.IO.Ports.SerialPort est utile pour le dépannage de la connectivité du scanner série, en particulier autour des paramètres ReadTimeout et WriteTimeout. Pour assurer la conformité réglementaire dans le secteur du commerce de détail, les spécifications générales GS1 définissent des plages de valeurs valides pour chaque identifiant d'application.

Comment étendre l'application aux plateformes mobiles et web ?

Le modèle d'interface du scanner illustré ci-dessus -- IScannerInput avec BarcodeScanned événement -- abstrait le matériel de la logique de traitement. L'échange d'implémentations permet d'exécuter le même code de validation et de génération sur différentes plateformes :

  • .NET MAUI fournit une implémentation de scanner basée sur une caméra pour les tablettes Android et iOS utilisées comme stations de réception mobiles
  • Blazor Server prend en charge la numérisation basée sur le navigateur avec un accès à la caméra JavaScript alimentant le même événement BarcodeScanned
  • Les implémentations natives Android et iOS offrent aux développeurs mobiles la possibilité de scanner avec l'appareil photo grâce au même décodeur IronBarcode côté serveur.

Pour les architectures natives du cloud, les étapes de validation et de génération d'étiquettes peuvent être exécutées en tant que fonctions Azure déclenchées par des messages de file d'attente, l'application de bureau servant uniquement de passerelle d'entrée du scanner. Cette séparation est particulièrement utile lorsque la logique d'impression des étiquettes doit être centralisée à des fins d'audit de conformité.

Quelles sont vos prochaines étapes ?

La création d'une application de lecteur de codes-barres USB avec IronBarcode comprend quatre étapes concrètes : la capture de l'entrée du clavier avec détection de synchronisation en rafale, la validation de la valeur scannée par le décodeur d'IronBarcode, la génération d'étiquettes de réponse au format requis et le traitement de volumes de numérisation élevés avec une file d'attente concurrente. Chaque étape est indépendante et peut être testée isolément.

À partir de là, envisagez d'étendre l'application avec la lecture de plusieurs codes-barres pour les scénarios de traitement par lots, l'optimisation de la zone de recadrage pour les entrées basées sur l'image ou la prise en charge des codes-barres MSI pour les équipements d'entrepôt plus anciens. La documentation IronBarcode couvre tous les formats pris en charge et les options de configuration avancées du lecteur.

Démarrez un essai gratuit pour obtenir une clé de licence de développement et commencez dès aujourd'hui à intégrer IronBarcode à votre application de numérisation.

Questions Fréquemment Posées

Qu'est-ce qu'IronBarcode et comment est-il lié aux scanners de codes-barres USB ?

IronBarcode est une bibliothèque qui permet aux développeurs de créer des applications C# robustes pour le scan de codes-barres USB. Elle offre des fonctionnalités telles que la validation de codes-barres, l'extraction de données et la génération de codes-barres.

IronBarcode peut-il valider les données de codes-barres d'un scanner USB ?

Oui, IronBarcode peut valider les données de codes-barres capturées par un scanner USB, garantissant l'intégrité et la précision des données dans vos applications C#.

Comment IronBarcode gère-t-il la génération de codes-barres ?

IronBarcode peut générer de nouveaux codes-barres à la volée, permettant aux développeurs de créer et d'imprimer des codes-barres facilement au sein de leurs applications C#.

Y a-t-il un support de gestion des erreurs dans IronBarcode pour le scan de codes-barres USB ?

Oui, IronBarcode inclut une gestion complète des erreurs pour gérer les problèmes courants qui peuvent survenir durant le scan et le traitement des codes-barres USB.

Quels types de codes-barres peuvent être numérisés avec IronBarcode ?

IronBarcode prend en charge le scan d'une large gamme de symbologies de codes-barres, incluant les QR codes, UPC, Code 39 et plus, le rendant polyvalent pour diverses applications.

IronBarcode peut-il extraire des informations structurées à partir de codes-barres scannés ?

Oui, IronBarcode peut extraire des informations structurées à partir de codes-barres scannés, aidant ainsi le traitement et la gestion efficaces des données.

Comment puis-je commencer à construire une application de scanner de codes-barres USB en C# ?

Pour commencer à construire une application de scanner de codes-barres USB en C#, vous pouvez utiliser IronBarcode ainsi que les exemples de code fournis et la documentation pour guider votre processus de développement.

Jordi Bardia
Ingénieur logiciel
Jordi est le plus compétent en Python, C# et C++, et lorsqu'il ne met pas à profit ses compétences chez Iron Software, il programme des jeux. Partageant les responsabilités des tests de produit, du développement de produit et de la recherche, Jordi apporte une immense valeur à l'amé...
Lire la suite

Équipe de soutien Iron

Nous sommes en ligne 24 heures sur 24, 5 jours sur 7.
Chat
Email
Appelez-moi