Zum Fußzeileninhalt springen
IRONBARCODE VERWENDEN

C# USB-Barcodescanner: Erstellen Sie eine vollständige Scan-Anwendung

USB-Barcodescanner werden von C#-Anwendungen als Standard-Tastatureingabegeräte verwendet und senden die gescannten Daten als eingegebene Zeichen, gefolgt von einem Tastendruck auf die Eingabetaste. Dieses HID-Tastatur-Wedge-Verhalten macht die Integration unkompliziert – Ihre Anwendung empfängt Texteingaben ohne dass ein spezieller Treiber oder ein SDK erforderlich ist. IronBarcode verarbeitet diese Rohdaten, um Formate zu validieren, strukturierte Daten zu extrahieren und Antwort-Barcodes zu generieren. So wird aus einem einfachen Scanvorgang eine vollständige Datenpipeline für Bestandsverwaltung, Kassensysteme im Einzelhandel und Logistik-Tracking-Systeme.

Einzelhandel, Lagerhaltung und Fertigung – alle sind auf ein genaues und schnelles Scannen von Barcodes angewiesen. Wenn ein Entwickler einen USB-Scanner an eine Windows Forms- oder WPF-Anwendung anschließt, verhält sich der Scanner identisch zu einer Tastatur – die Daten kommen in einem Textfeld an, und das Drücken der Eingabetaste signalisiert, dass ein vollständiger Barcode empfangen wurde. Die Herausforderung besteht nicht in der Datenerfassung; Es wird korrekt verarbeitet. Die Barcode-Validierungsfunktion von IronBarcode prüft die Formatintegrität, extrahiert Felder wie Chargennummern oder GS1-Anwendungskennungen und kann daraufhin sofort einen neuen Barcode generieren .

Diese Anleitung führt Sie Schritt für Schritt durch die Entwicklung einer produktionsreifen C#-USB-Barcodescanner-Anwendung. Sie installieren die Bibliothek, erfassen Scannereingaben, validieren Barcode-Formate, generieren Antwortbezeichnungen und erstellen einen Prozessor für hohe Scanvolumen mit Warteschlangen. Jeder Abschnitt enthält vollständigen, ausführbaren Code, der auf .NET 10 abzielt und gegebenenfalls Top-Level-Anweisungen verwendet.

Wie funktionieren USB-Barcodescanner mit C#?

Warum vereinfacht der HID-Tastaturkeilmodus die Integration?

Die meisten USB-Barcodescanner werden standardmäßig im HID-Tastatur-Wedge-Modus ausgeliefert. Wenn Sie ein solches Gerät an einen Windows-Rechner anschließen, erkennt das Betriebssystem es sowohl als USB-Speichergerät (zur Konfiguration) als auch als Tastatur (zur Dateneingabe). Beim Scannen eines Barcodes übersetzt das Gerät den dekodierten Barcode-Wert in Tastatureingaben und sendet diese an das jeweilige Anwendungsfenster, das den Fokus hat, wobei am Ende ein Zeilenumbruch angehängt wird.

Aus der Sicht eines C#-Entwicklers bedeutet dies, dass keine herstellerspezifischen SDKs, COM-Bibliotheken oder spezielle USB-APIs benötigt werden. Ein Standard-TextBox-Steuerelement mit einem KeyDown-Handler genügt, um Eingaben zu erfassen. Die größte Herausforderung bei der Integration besteht darin, die Eingabe durch den Scanner von der tatsächlichen Tastatureingabe zu unterscheiden. Scanner liefern typischerweise alle Zeichen in einem sehr kurzen Moment – ​​oft unter 50 Millisekunden –, während menschliches Tippen die Tastenanschläge über Hunderte von Millisekunden verteilt. Das Timing der Tastenanschläge ist eine zuverlässige Methode, um versehentliche Tastendrücke herauszufiltern.

Professionelle Scanner unterstützen außerdem serielle Schnittstellen (RS-232 oder virtueller COM-Port) und direkte USB-HID-Modi, die Ihnen mehr Kontrolle über Präfix-/Suffixzeichen und Scan-Trigger geben. Das untenstehende Schnittstellenmuster behandelt beide Fälle:

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

Der entscheidende Punkt ist der Burst-Timer in der Tastatur-Wedge-Implementierung. Es wird bei jedem Tastendruck zurückgesetzt und nur ausgelöst, wenn keine Zeichen mehr eintreffen – das bedeutet, dass bei echten Tastaturbenutzern, die langsam tippen, die unvollständige Eingabe verworfen und nicht wie ein Barcode-Scan behandelt wird.

Wie handhabt man verschiedene Scannermarken?

In Enterprise werden häufig verschiedene Scanner von Honeywell, Zebra (ehemals Symbol/Motorola) und Datalogic auf derselben Etage eingesetzt. Jeder Anbieter hat seine eigenen Standard-Abschlusszeichen, Baudraten und Präfix-/Suffixkonventionen. Ein Konfigurationsmodell sorgt für Flexibilität Ihrer Anwendung:

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

Durch das Speichern dieser Konfigurationen in einer Einstellungsdatei oder Datenbank können die Lagermitarbeiter die Scannermodelle austauschen, ohne dass eine erneute Bereitstellung erforderlich ist. Das Feld ScannerType steuert, welche IScannerInput Implementierung beim Start instanziiert wird.

Wie installiert man IronBarcode in einem C#-Projekt?

Wie kann IronBarcode am schnellsten über NuGet hinzugefügt werden?

Öffnen Sie die Paketmanager-Konsole in Visual Studio und führen Sie den Befehl aus:

Install-Package IronBarCode
Install-Package IronBarCode
SHELL

Alternativ können Sie die .NET -Befehlszeilenschnittstelle verwenden:

dotnet add package IronBarCode
dotnet add package IronBarCode
SHELL

Beide Befehle laden die aktuelle Version von NuGet herunter und fügen den Assemblyverweis zu Ihrer Projektdatei hinzu. Die Bibliothek ist for .NET Standard 2.0 ausgelegt und funktioniert daher ohne zusätzliche Kompatibilitätsschnittstellen unter .NET Framework 4.6.2 bis .NET 10.

Nach der Installation müssen Sie Ihren Lizenzschlüssel festlegen, bevor Sie eine beliebige IronBarcode -Methode aufrufen. Für Entwicklungs- und Evaluierungszwecke ist ein kostenloser Testschlüssel auf derIronBarcode -Lizenzseite erhältlich:

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

Für containerisierte Bereitstellungen arbeitet IronBarcode mit Docker unter Linux zusammen , und für Cloud-Funktionen unterstützt es AWS Lambda und Azure Functions .

Wie validiert man gescannte Barcodes mit IronBarcode?

Welcher Ansatz ist für die Formatverifizierung der richtige?

IronBarcode unterstützt über 30 Barcode-Symbologien, darunter Code 128 , EAN-13 , Code 39 , QR-Codes und Data Matrix . Bei USB-Scanneranwendungen wird die gescannte Zeichenkette durch das Validierungsmuster als Barcode-Bild neu codiert und sofort wieder durch den Decoder eingelesen. Dieser Roundtrip bestätigt, dass die Zeichenkette ein gültiger Wert für das angegebene Format ist:

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

Bei GS1-128-Barcodes , die in Supply-Chain-Anwendungen verwendet werden, enthält die gescannte Zeichenkette Anwendungsidentifikatorpräfixe in Klammern, wie z. B. (01) für GTIN und (17) für das Ablaufdatum. IronBarcode analysiert diese Anwendungsbezeichner automatisch, wenn Sie BarcodeEncoding.GS1_128 angeben.

Welche EAN-13-Prüfsummenlogik sollten Entwickler implementieren?

Kassensysteme im Einzelhandel müssen häufig die Prüfziffern der EAN-13-Nummer separat verifizieren, bevor der Wert an eine Preisabfrage übergeben wird. Die Luhn-Prüfsumme für EAN-13 verwendet abwechselnd die Gewichtungen 1 und 3 für die ersten 12 Ziffern.

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

Diese rein logische Prüfung wird vor der Kodierung durchgeführt, um den Aufwand der Bildgenerierung für jeden Scan in einer Einzelhandelsumgebung mit hohem Durchsatz zu vermeiden. Gemäß der GS1-Spezifikation ist der Prüfziffernalgorithmus für UPC-A (12 Ziffern) identisch, wenn man die führende Null weglässt.

Wie generiert man Antwort-Barcodes aus gescannten Eingaben?

Wann sollte eine Anwendung nach einem Scan neue Barcodes erstellen?

Ein gängiges Muster bei der Warenannahme im Lager ist der Arbeitsablauf "Scannen und Neuetikettieren": Ein eingehender Artikel trägt einen Lieferanten-Barcode (oft EAN-13 oder ITF-14), und das Lagerverwaltungssystem muss ein internes Code-128-Etikett mit eigenen Standort- und Chargencodes drucken. Die Generierungsfunktionen von IronBarcode erledigen dies in wenigen Zeilen:

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

Das Speichern als PDF ist besonders nützlich für Etikettendrucker, die PDF-Eingaben über eine Netzwerkfreigabe akzeptieren. Sie können auch als SVG exportieren, um qualitativ hochwertige Thermodrucketiketten auszugeben, oder als Byte-Stream exportieren, um ihn direkt an eine Etikettendrucker-API zu senden.

IronBarcode unterstützt umfangreiche Stilanpassungen, darunter benutzerdefinierte Farben, Randanpassungen , lesbare Textüberlagerungen und, bei QR-Codes, die Einbettung von Logos für markengekennzeichnete mobile Etiketten.

![Windows Forms-Anwendungsoberfläche, die die Dual-Barcode-Generierungsfunktionen von IronBarcode demonstriert. Die Benutzeroberfläche zeigt die erfolgreiche Generierung sowohl eines linearen Code-128-Barcodes als auch eines QR-Codes für die Inventarnummer "INV-20250917-helloworld". Über das Eingabefeld oben können Benutzer benutzerdefinierte Inventarcodes eingeben. Mit der Schaltfläche "Generieren" lassen sich die Barcodes erstellen. Die Erfolgsmeldung "Element erfolgreich verarbeitet – Etiketten generiert" bestätigt den Abschluss des Vorgangs. Der Code-128-Barcode ist als primäres Format für die Bestandsverfolgung gekennzeichnet, während der darunter stehende QR-Code als mobile Alternative dient. Die Anwendung verwendet einen Professional grauen Hintergrund mit klarer visueller Hierarchie und demonstriert, wie IronBarcode Entwicklern die Erstellung von Barcode-Generierungssystemen für verschiedene Formate zur umfassenden Bestandsverwaltung ermöglicht.

Wie entwickelt man eine vollständige Anwendung zum Scannen großer Datenmengen?

Wie sieht eine Implementierung auf Basis einer Produktionswarteschlange aus?

Bei Anwendungen, die Dutzende von Scans pro Minute verarbeiten, wird ein einfacher synchroner Handler im UI-Thread zum Flaschenhals. Das unten beschriebene Muster entkoppelt die Scan-Erfassung von der Verarbeitung mithilfe eines ConcurrentQueue<t> und einer Hintergrundverarbeitungsschleife. Die asynchrone API von IronBarcode übernimmt die Validierung, ohne die Benutzeroberfläche zu blockieren:

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

Der SemaphoreSlim begrenzt die Anzahl gleichzeitiger Validierungsaufgaben auf die Anzahl logischer Prozessoren und verhindert so die Entstehung unkontrollierter Threads während Burst-Scanning-Ereignissen. Die BeginInvoke-Aufrufe führen UI-Aktualisierungen sicher zurück zum Hauptthread.

Wie optimiert man die Leistung für unterschiedliche Scanvolumina?

Die Eigenschaft BarcodeReaderOptions.Speed akzeptiert ReadingSpeed.Schneller, ReadingSpeed.Ausgewogen und ReadingSpeed.Ausführlich. Bei USB-Scannereingaben, bei denen der Zeichenkettenwert bereits bekannt ist, ist Ausgewogen geeignet – der Decoder muss nur das Format bestätigen, nicht aber einen Barcode in einem Bild finden. Laut der Dokumentation zur Lesegeschwindigkeit von IronBarcode werden im Modus Schneller einige Verzerrungskorrekturalgorithmen übersprungen, was für eine saubere Scannerausgabe unbedenklich ist, aber dazu führen kann, dass beschädigte Barcodes in bildbasierten Szenarien nicht erkannt werden.

Die folgende Tabelle fasst zusammen, wann welcher Geschwindigkeitsmodus verwendet werden sollte:

Lesegeschwindigkeitsmodi von IronBarcode und ihre jeweiligen Anwendungsfälle
Geschwindigkeitsmodus Am besten für Abtausch
Schneller Sauberer USB-Scannereingang, hoher Durchsatz Kann stark beschädigte oder schiefe Barcodes nicht erkennen
Ausgewogen Gemischte Eingabe – USB-Scanner Plus Bildimporte Mäßige CPU-Auslastung, gute Genauigkeit
Ausführlich Beschädigte Etiketten, kontrastarmer Druck, PDF-Importe Höhere CPU-Auslastung, geringster Durchsatz

Für Anwendungen, die neben USB-Scannereingaben auch Bilder oder PDFs verarbeiten, kann IronBarcode Barcodes aus PDF-Dokumenten und mehrseitigen TIFF-Dateien über dieselbe API-Schnittstelle IronBarcode .

Professional Windows Forms Barcode-Scanner-Anwendung, die die Echtzeit-Inventarverfolgungsfunktionen von IronBarcode demonstriert. Die Benutzeroberfläche zeichnet sich durch ein übersichtliches Zwei-Panel-Design mit einer eleganten dunkelblauen Kopfzeile aus. Im linken Bereich wird eine Scanverlaufsliste angezeigt, die vier erfolgreich gescannte Inventarartikel (INV-001 bis INV-004) mit genauen Zeitstempeln und Scanstatusanzeigen anzeigt. Jeder Artikel enthält detaillierte Metadaten wie Barcode-Typ und Konfidenzniveau. Im rechten Bereich wird ein dynamisch generierter Zusammenfassungs-Barcode angezeigt, der Artikel: 4 mit Professional Styling und korrekten Rändern anzeigt. Die Aktionsschaltflächen am unteren Rand umfassen Liste löschen, Daten exportieren und Etiketten drucken für eine vollständige Bestandsverwaltung. Die Statusleiste zeigt Scanner: Verbunden an. | Modus: Kontinuierlich | Letzter Scan: vor 2 Sekunden, was die Echtzeit-Überwachungsfunktionen der Anwendung und das Professional , unternehmensgerechte Design demonstriert, das IronBarcode für Produktionsinventursysteme ermöglicht.

Wie geht man mit Sonderfällen und Fehlern in Scanneranwendungen um?

Welche Fehlerszenarien sollten Entwickler erwarten?

USB-Scanner-Anwendungen versagen auf vorhersehbare Weise. Die häufigsten Probleme und ihre Abhilfemaßnahmen sind:

Scannerverbindung unterbrochen - Wenn ein USB-Scanner ausgesteckt wird, verliert das Tastatur-Wedge-TextBox seine virtuelle Tastatur. Die einfachste Abhilfemaßnahme ist ein periodischer Timer, der _inputBox.Focused überprüft und ihn neu fokussiert, wenn der Scanner noch in der Liste der verbundenen HID-Geräte aufgeführt ist. Bei seriellen Scannern erkennt SerialPort.GetPortNames() eine erneute Verbindung.

Mehrdeutige Barcode-Formate – Einige Produkte tragen Barcodes, die in mehreren Symbologien gültig sind. Eine 12-stellige Zeichenkette ist beispielsweise ein gültiger UPC-A-Code und gleichzeitig ein gültiger Code 128. Die Angabe von ExpectBarcodeTypes in BarcodeReaderOptions beschränkt den Decoder auf die von Ihnen erwarteten Formate und beseitigt Mehrdeutigkeiten. Der IronBarcode Leitfaden zur Fehlerbehebung enthält formatspezifische Erkennungstipps.

Ungültige Formatausnahmen -- Wenn BarcodeWriter.CreateBarcode eine Zeichenkette empfängt, die gegen die Regeln der ausgewählten Kodierung verstößt (z. B. alphabetische Zeichen in einem nur numerischen EAN-13-Feld), wird eine IronBarCode.Exceptions.InvalidBarcodeException-Ausnahme ausgelöst. Durch das Einbetten des Aufrufs in einen try-catch-Block und den Rückgriff auf einen Validierungspfad, der nur Zeichenketten zulässt, kann die Anwendung weiterlaufen.

Kollisionen der Tastenanschlagzeiten – In Umgebungen, in denen die Bediener auch manuell in dasselbe Textfeld tippen, ist der zuvor beschriebene Burst-Timer-Ansatz die primäre Verteidigungsmethode. Eine weitere Schutzmaßnahme ist die Mindestlänge: Die meisten realen Barcodes bestehen aus mindestens 8 Zeichen, daher können kürzere Zeichenketten als Tastatureingabe behandelt werden.

Die Microsoft .NET -Dokumentation zu System.IO.Ports.SerialPort ist hilfreich bei der Fehlersuche in Bezug auf die serielle Scannerverbindung, insbesondere im Zusammenhang mit den Einstellungen ReadTimeout und WriteTimeout. Zur Einhaltung gesetzlicher Vorschriften im Einzelhandel definieren die GS1 General Specifications gültige Wertebereiche für jede Anwendungskennung.

Wie lässt sich die Anwendung auf mobile und Web-Plattformen erweitern?

Das oben gezeigte Scanner-Schnittstellenmuster -- IScannerInput mit BarcodeScanned Ereignis -- abstrahiert die Hardware von der Verarbeitungslogik. Durch den Austausch der Implementierungen kann derselbe Validierungs- und Generierungscode auf verschiedenen Plattformen ausgeführt werden:

  • .NET MAUI bietet eine kamerabasierte Scanner-Implementierung für Android- und iOS-Tablets, die als mobile Empfangsstationen verwendet werden.
  • Blazor Server unterstützt browserbasiertes Scannen mit JavaScript Kamerazugriff, der in dasselbe BarcodeScanned Ereignis eingespeist wird.
  • Native Implementierungen für Android und iOS bieten mobilen Entwicklern die Möglichkeit, mit der Kamera zu scannen, wobei im Backend derselbe IronBarcode -Decoder verwendet wird.

Bei Cloud-nativen Architekturen können die Validierungs- und Labelgenerierungsschritte als Azure Functions ausgeführt werden, die durch Warteschlangennachrichten ausgelöst werden, wobei die Desktop-Anwendung lediglich als Eingabegateway für den Scanner fungiert. Diese Trennung ist besonders dann nützlich, wenn die Logik für den Etikettendruck im Rahmen von Compliance-Audits zentralisiert werden muss.

Was sind Ihre nächsten Schritte?

Die Entwicklung einer USB-Barcode-Scanner-Anwendung mit IronBarcode umfasst vier konkrete Schritte: Erfassung der Tastatureingabe mittels Burst-Timing-Erkennung, Validierung des gescannten Werts durch den Decoder von IronBarcode, Generierung von Antwortbezeichnungen im erforderlichen Format und Verarbeitung großer Scanvolumina mit einer parallelen Warteschlange. Jede Phase ist unabhängig und kann isoliert getestet werden.

Erwägen Sie von hier aus, die Anwendung um das Lesen mehrerer Barcodes für Stapelverarbeitungsszenarien, die Optimierung des Bildausschnitts für bildbasierte Eingaben oder die Unterstützung von MSI-Barcodes für ältere Lagertechnik zu erweitern. Die IronBarcode Dokumentation umfasst alle unterstützten Formate und erweiterte Konfigurationsoptionen für das Lesegerät.

Starten Sie eine kostenlose Testphase , um einen Entwicklerlizenzschlüssel zu erhalten und IronBarcode noch heute in Ihre Scan-Anwendung zu integrieren.

Häufig gestellte Fragen

Was ist IronBarcode und wie hängt es mit USB-Barcodescannern zusammen?

IronBarcode ist eine Bibliothek, die es Entwicklern ermöglicht, robuste C#-Anwendungen für USB-Barcodescanning zu erstellen. Sie bietet Funktionen wie Barcode-Validierung, Datenextraktion und Barcode-Generierung.

Kann IronBarcode Barcodedaten von einem USB-Scanner validieren?

Ja, IronBarcode kann von einem USB-Scanner erfasste Barcodedaten validieren und so die Datenintegrität und -genauigkeit in Ihren C#-Anwendungen sicherstellen.

Wie behandelt IronBarcode die Barcode-Generierung?

IronBarcode kann neue Barcodes "on-the-fly" generieren und ermöglicht es Entwicklern, Barcodes einfach innerhalb ihrer C#-Anwendungen zu erstellen und zu drucken.

Gibt es eine Unterstützung für die Fehlerbehandlung in IronBarcode für USB-Barcodescanning?

Ja, IronBarcode beinhaltet eine umfassende Fehlerbehandlung, um häufige Probleme zu bewältigen, die während des USB-Barcodescannings und der -verarbeitung auftreten können.

Welche Arten von Barcodes können mit IronBarcode gescannt werden?

IronBarcode unterstützt das Scannen einer Vielzahl von Barcode-Symbologien, einschließlich QR-Codes, UPC, Code 39 und mehr, was es vielseitig für verschiedene Anwendungen macht.

Kann IronBarcode strukturierte Informationen aus gescannten Barcodes extrahieren?

Ja, IronBarcode kann strukturierte Informationen aus gescannten Barcodes extrahieren, was eine effiziente Datenverarbeitung und -verwaltung unterstützt.

Wie kann ich mit dem Aufbau einer USB-Barcodescanner-Anwendung in C# beginnen?

Um mit dem Aufbau einer USB-Barcodescanner-Anwendung in C# zu beginnen, können Sie IronBarcode zusammen mit den bereitgestellten Codebeispielen und der Dokumentation verwenden, um Ihren Entwicklungsprozess zu leiten.

Jordi Bardia
Software Ingenieur
Jordi ist am besten in Python, C# und C++ versiert. Wenn er nicht bei Iron Software seine Fähigkeiten einsetzt, programmiert er Spiele. Mit Verantwortung für Produkttests, Produktentwicklung und -forschung trägt Jordi mit immensem Wert zur kontinuierlichen Produktverbesserung bei. Die abwechslungsreiche Erfahrung hält ihn gefordert und engagiert, ...
Weiterlesen

Iron Support Team

Wir sind 24 Stunden am Tag, 5 Tage die Woche online.
Chat
E-Mail
Rufen Sie mich an