Click here to Skip to main content
Click here to Skip to main content
Go to top

Using a bar code scanner in .NET

, 23 Jul 2014
Rate this:
Please Sign up or sign in to vote.
Bar code scanner integration with WPF or WinForms.

Introduction

Most bar code scanners emulate keyboards. This allows them to be easily used in any application. The user simply needs to put the focus on any text input control and then scan a bar code.

This same behaviour also allows the user to scan bar codes into fields not intended for scanning and can cause problem. This method does not allow the application to take instant action when a scan is received because the application has no way of distinguishing the bar code scanner input from the keyboard.

Many vendors have their own APIs which can be used to distinguish the bar code scanner from the keyboard. In the real world, there are thousands of bar code scanners and relying on vendor specific APIs is not practical. Many of the generic or clone scanners which are now a common commodity have no API and rely solely on keyboard emulation which further complicates the issue.

Fortunately, there is an easy yet not well known method for detecting distinct input from the bar code scanner. This allows the user to scan bar codes without needing to put the focus on a special field, or activate buttons or menu items before each scan.

Background

One of my projects required integration with POS peripherals for sales, receiving, inventory, and other standard retail functions. Recently we needed to integrate bar code readers. Previously we had used bar code scanners for lookups, serial number entry, etc. But users were required to tell the software first by clicking a button, or selecting a text box first and then scanning the code. The software did not know the difference between the scanner and the keyboard. The application just took the text sent to it and was oblivious as to wheter it came from the keyboard or a bar code scanner.

This approach permits a lot of user mistakes. It is also inefficient. There are ways to directly integrate with bar code scanners using third party libraries, SDKs, or OPOS. But this seemed like a lot of fuss just to be able to get data from the bar code scanner and know it came from the bar code scanner.

Many suggested to use OPOS. In the past we had used OPOS in the past for interacting with high speed thermal printers. OPOS however relies on individual setup on each machine, and a separate OPOS driver for each piece of hardware. Vendor support for OPOS is varied, and very often the vendor drivers are shoddy and not well supported. Bar code scanners however are lower cost items and in a given site ther eare often many different brands of scanners. In the end we later swtiched to raw support for the thermal printers as well and completely eliminated OPOS and all its hassles with it.

After more research I learned that many users resorted to the WinAPI and keyboard hooks. These solutions required a lot of external calls and many relied on Windows messages which did not work as well with WPF. This method also required the developer to uniquely identify they device specifically on each machine.

First Attempt

Bar code scanners can be programmed to send a prefix and suffix for each scan. Many scanners allow you to program them with a verity of characters. For widest compatibilty STX (start of text, 0x02 ASCII) and ETX (end of text, 0x03 ASCII) are the best choices.

I created a KeyDown event in a WPF app and scanned a bar code. The first key I received was LeftCtrl. LeftCtrl??? Obviously WPF didn't know how to handle low ASCII codes that keyboards were never designed to send. Part of this complication is because WPF generally deals with scan codes and not ASCII codes. Not all ASCII codes can map to scan codes.

I gave up this approach and tried many of the more complex WinAPI approaches to try to access the raw input from the bar code scanner. Most had problems with WPF and required a lot of adaptation because they were written for WinForms and relied on Windows messages.

I succeeeded wtih one test and became excited. But then I ran my first test and got a code of 162. 162 is the scan code for LeftCtrl. :(

Retry

Back to WPF and a simple PreviewKeyUp. I dug a bit deeper beyond the first character and noticed a pattern. I hoped that I could detect this pattern reliably and intercept the keystrokes. I made a program to log key ups and downs and realized quickly that STX (0x02) was being translated to:

  • Down: LeftCtrl
  • Down: B
  • Up: B
  • Up: LeftCtrl

Then it hit me. My previous assumptions were wrong. Windows was seeing STX (0x02). I previously assumed Windows was getting confused. In fact it was doing a bit of translation. In the older times, Ctrl + <A-Z letter> was mapped to 1-26 in ASCII. That is, Ctrl-A was equivalent to 0x01. On many older 8 bit computers you could press Ctrl-M and the computer would see it the same as Enter (0x0D). So Windows was seeing the STX (0x02) from the bar code scanner and translating it into a series of key code scans that represented Ctrl-B.

Now I had something I could work with.

The Code

I added two events to my main WPF window: PreviewKeyUp and PreviewKeyDown. I kept track of the Ctrl key state and then looked for a B to detect Ctrl-B. From there I collected all input until I found a Ctrl-C (ETX, 0x03) sequence. Note that most bar code readers do not send these sequences by default, but nearly all can be easily configured to do so.

From Ctrl-B to the Ctrl-C, I assumed all input was from the bar code scanner and set the event handled property so other events in my program would not see the data. At the end, I called an event and handed the data off to my program.

Demo

In this demo, the sole purpose of the edit field is to show that normal keyboard input is taken, but bar code scanner input is not. The listbox on the left shows the raw key scan sequences. Bar code results are shown in the listbox on the right.

The demo was built in C#, WPF, and Visual Studio 2010. It can be very easily used with VB.NET, WinForms, and other versions of Visual Studio.

BarCodeScannerReader/Untitled.png

Reuse

This method can be easily encapsulated into a class for easy reuse on any window. In my application, all of our WPF windows descend from a common base class, so I have put the functionality there. For each window, I simply need to add this in the constructor:

ScanReceived = Scan;
void Scan(string aData) {
  MessageBox.Show("Scan received: " + aData);
}

Result

Without the use of WinAPI, invasive code, or complex code, I found a method to reliably interpret bar code scanner input. In fact the actual code fits easily on a screen. With this method, there is no need to identify to the code which device is the bar code scanner. The code simply looks for patterns in the key presses and separates the data out.

Caveat

There is one small caveat. Ctrl-B cannot be used in your application for menus or other hot key functions. The code relies on this to detect the start of input from the bar code scanner. The code also looks for Ctrl-C, but only after a Ctrl-B. At other times, it ignores Ctrl-C, so the commonly used shortcut for copy to clipboard does not conflict with the use of this technique.

In most applications this is not an issue. However if you need Ctrl-B for something like Bold in a word processor, it could be a problem for you. To get around this the code will need to be upgraded to look for Ctrl-B and then wait for a certain amount of time and if no characters appear followed by a Ctrl-C, it could thne pass on the Ctrl-B to the application as normal.

Known Issues

There are a few issues when other keypress handlers exist on the window. I have addressed these in my production code and will update the demo as time permits.

Future Expansion

Bar code scanners can also be programmed to issue other prefixes to identify the type of code scanned, i.e., UPC vs. Code39. With the products we deal with, this is useful because if a UPC is scanned we know it identifies the product, while Code39 and other non UPC/EAN codes typically represent serial numbers of the item. This allows users to receive items very quickly without the need to identify first what they want to do to the software, and instead the software can infer the user intended actions based on the active window. I have expanded my code to recognize other prefixes and respond with other available events.

License

This article, along with any associated source code and files, is licensed under The BSD License

Share

About the Author

Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"
www.KudzuWorld.com
 
Formerly the Regional Developer Adviser (DPE) for Microsoft Middle East and Africa, he was responsible for 85 countries spanning 4 continents and 10 time zones. Now Chad is a Microsoft MVP.
 
Chad is the chair of several popular open source projects including Indy and Cosmos (C# Open Source Managed Operating System).
 
Chad is the author of the book Indy in Depth and has contributed to several other books on network communications and general programming.
 
Chad has lived in Canada, Cyprus, Switzerland, France, Jordan, Russia, Turkey, and the United States. Chad has visited more than 60 countries, visiting most of them several times.

Comments and Discussions

 
QuestionI noticed a case that fails PinmemberMember 1008561625-Sep-14 7:35 
QuestionSubject: Righthand listbox in app not being populated when using Denso AT21Q-SM scanner PinmemberMember 85914699-Aug-14 11:10 
AnswerRe: Subject: Righthand listbox in app not being populated when using Denso AT21Q-SM scanner PinmemberChad Z. Hower aka Kudzu9-Aug-14 11:34 
QuestionIn WinForms listBox2 didn't show the mScanData value Pinmembersky391317-Jul-14 8:09 
AnswerRe: In WinForms listBox2 didn't show the mScanData value PinmemberChad Z. Hower aka Kudzu17-Jul-14 8:18 
GeneralRe: In WinForms listBox2 didn't show the mScanData value Pinmembersky391320-Jul-14 6:47 
GeneralRe: In WinForms listBox2 didn't show the mScanData value PinmemberChad Z. Hower aka Kudzu20-Jul-14 6:50 
QuestionDoes Not Work With Windows 7 PinmemberDevious227-Jun-14 3:09 
AnswerRe: Does Not Work With Windows 7 PinmemberChad Z. Hower aka Kudzu27-Jun-14 3:11 
QuestionThanks PinmemberPaul Nielsen12-Nov-13 14:27 
Questionbarcode scanner Pinmembercindy3131-Sep-13 21:34 
AnswerRe: barcode scanner PinmemberChad Z. Hower aka Kudzu2-Sep-13 1:36 
AnswerRe: barcode scanner Pinmembercstasyof30-Jul-14 23:27 
GeneralRe: barcode scanner PinmemberChad Z. Hower aka Kudzu31-Jul-14 3:05 
Questionread barcode in .NET Pinmembercoder121221-Aug-13 16:25 
AnswerRe: read barcode in .NET PinmemberChad Z. Hower aka Kudzu24-Aug-13 10:23 
GeneralMessage from Arul PinmemberK.Arulselvam15-Mar-13 20:10 
QuestionThanks for article PinmemberK.Arulselvam15-Mar-13 20:02 
AnswerRe: Thanks for article PinmemberChad Z. Hower aka Kudzu16-Mar-13 2:07 
Questionpos bar code Pinmembersybil_11-Oct-12 22:36 
Question.net barcode reader PinmemberZacbr17-Sep-12 18:56 
AnswerRe: .net barcode reader PinmemberChad Z. Hower aka Kudzu18-Sep-12 2:44 
QuestionDoes all barcode scanners have default Prefix and Suffix by default ? Pinmembertsonev711-Jul-12 1:36 
AnswerRe: Does all barcode scanners have default Prefix and Suffix by default ? PinmemberChad Z. Hower aka Kudzu11-Jul-12 6:53 
Scanners by default dont send prefix and suffix, but Ive never seen one that could not be programmed to do so. To program it you scan in special bar codes. Find the model and you can usually find the programming guide online, print out the specific pages, and scan in the codes.
Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"
 
My Technical Stuff:
http://www.KudzuWorld.com
 
My Blogs:
http://www.KudzuWorld.com/blogs/

GeneralRe: Does all barcode scanners have default Prefix and Suffix by default ? [modified] Pinmembertsonev711-Jul-12 23:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140926.1 | Last Updated 23 Jul 2014
Article Copyright 2011 by Chad Z. Hower aka Kudzu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid