Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / Windows Forms

Using a bar code scanner in .NET

Rate me:
Please Sign up or sign in to vote.
4.78/5 (51 votes)
23 Jul 2014BSD7 min read 436.7K   28.4K   137   110
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:

C#
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


Written By
Cyprus Cyprus
Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"

I am a former Microsoft Regional DPE (MEA) covering 85 countries, former Microsoft Regional Director, and 10 Year Microsoft MVP.

I have lived in Bulgaria, Canada, Cyprus, Switzerland, France, Jordan, Russia, Turkey, The Caribbean, and USA.

Creator of Indy, IntraWeb, COSMOS, X#, CrossTalk, and more.

Comments and Discussions

 
GeneralMy vote of 5 Pin
NickPearce23-May-22 11:41
NickPearce23-May-22 11:41 
QuestionGreat informative article Pin
coarist15-Jan-19 1:58
coarist15-Jan-19 1:58 
AnswerRe: Great informative article Pin
Chad Z. Hower aka Kudzu1-May-19 10:12
Chad Z. Hower aka Kudzu1-May-19 10:12 
QuestionWould this work with Xamarin.Forms Pin
oniDino3-Aug-18 7:22
oniDino3-Aug-18 7:22 
AnswerRe: Would this work with Xamarin.Forms Pin
Chad Z. Hower aka Kudzu1-May-19 10:07
Chad Z. Hower aka Kudzu1-May-19 10:07 
QuestionI never get anything displayed in the right list box Pin
oniDino3-Aug-18 8:00
oniDino3-Aug-18 8:00 
AnswerRe: I never get anything displayed in the right list box Pin
Chad Z. Hower aka Kudzu1-May-19 10:09
Chad Z. Hower aka Kudzu1-May-19 10:09 
QuestionUsing a bar code scanner in .NET Pin
Ross S Fink1-Aug-18 11:18
Ross S Fink1-Aug-18 11:18 
AnswerRe: Using a bar code scanner in .NET Pin
Chad Z. Hower aka Kudzu1-May-19 10:12
Chad Z. Hower aka Kudzu1-May-19 10:12 
QuestionMain Window Pin
Member 1361835711-Jan-18 12:16
Member 1361835711-Jan-18 12:16 
AnswerRe: Main Window Pin
Chad Z. Hower aka Kudzu12-Jul-18 6:18
Chad Z. Hower aka Kudzu12-Jul-18 6:18 
QuestionNo Difference Pin
Psynister14-Oct-16 7:22
Psynister14-Oct-16 7:22 
AnswerRe: No Difference Pin
Chad Z. Hower aka Kudzu1-May-19 10:11
Chad Z. Hower aka Kudzu1-May-19 10:11 
Questiondynamic prefix Pin
Member 1259749221-Jun-16 23:35
Member 1259749221-Jun-16 23:35 
AnswerRe: dynamic prefix Pin
Chad Z. Hower aka Kudzu24-Jun-16 5:06
Chad Z. Hower aka Kudzu24-Jun-16 5:06 
QuestionReuse in app Pin
Dzilupl9-Dec-15 2:07
Dzilupl9-Dec-15 2:07 
AnswerRe: Reuse in app Pin
Chad Z. Hower aka Kudzu9-Dec-15 6:41
Chad Z. Hower aka Kudzu9-Dec-15 6:41 
GeneralRe: Reuse in app Pin
Dzilupl9-Dec-15 21:03
Dzilupl9-Dec-15 21:03 
GeneralRe: Reuse in app Pin
Chad Z. Hower aka Kudzu10-Dec-15 4:27
Chad Z. Hower aka Kudzu10-Dec-15 4:27 
Questionimplementing key in class Pin
sarath para23-Nov-15 4:07
sarath para23-Nov-15 4:07 
AnswerRe: implementing key in class Pin
Chad Z. Hower aka Kudzu7-Dec-15 3:38
Chad Z. Hower aka Kudzu7-Dec-15 3:38 
GeneralRe: implementing key in class Pin
sarath para5-Jan-16 21:41
sarath para5-Jan-16 21:41 
GeneralRe: implementing key in class Pin
Chad Z. Hower aka Kudzu6-Jan-16 8:31
Chad Z. Hower aka Kudzu6-Jan-16 8:31 
QuestionThanks for sharing this Pin
sarath para23-Nov-15 4:07
sarath para23-Nov-15 4:07 
QuestionFocus needed? Pin
itreniets24-Nov-14 22:29
itreniets24-Nov-14 22:29 

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

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