Distinguishing Barcode Scanners from the Keyboard in WinForms

Like any business, small or otherwise, we use barcodes for lots of things–for picking orders, for looking up totes, for processing returns, and for checking in inventory, to name but a few–and so our internal Windows Forms-based application asks for barcodes a lot:

To scan a barcode, just focus that textbox and use the scan gun. Easy!

To scan a barcode, just focus that textbox and use the scan gun. Easy!

We have three different types of barcode scan guns at work, but they all work in more or less the same way: they show up as a USB HID device in Windows, and when you scan a barcode, Windows and WinForms applications simply see it as if someone were typing a bunch of numbers on the keyboard really quickly. This makes integration easy: wherever you have a Textbox, you can click on it and scan a barcode and it just works.

By scanning barcodes everywhere, we reduce miscounts and improve our accuracy. But there is one part of this select-the-textbox-and-scan model that is incredibly irritating.

I was first alerted to the problem by my highly irritated coworker storming into my office. He was annoyed that he had been checking in inventory for a particularly large shipment and hadn’t noticed until the end of his work that he or the scan gun’s cord had jiggled the keyboard and caused the textbox to lose focus. The scan gun beeped happily when it read a barcode, but the warehouse computers lack sound and so there was no obvious way to alert him that, um, some of those last 100 barcode scans had been sent to an hwnd that doesn’t give a flying fart about them. The result? He had to start over.

The typical programmer response was “Well, make sure that the textbox actually has focus.” And this policy worked for a short while until I was the one checking in a particularly large shipment one day and happened to do the exact same thing. I was irritated, to say the least. Time to solve the problem.

Developing a strategy

So how would I like this to work? Well, I envision creating a class called BarcodeScannerListener. This class would expose a BarcodeScanned event that would, you know, be fired when a barcode was scanned no matter which control or form currently had focus; the event arguments would be something like BarcodeScannedEventArgs that contained the complete scanned barcode and, if we wanted to get real fancy, perhaps some additional information about the device. Then, all I have to do is pass this instance of BarcodeScannerListener around my application to interested parties (through dependency injection or some nonsense, or by making it a singleton), and I’d have cut out a lot of textbox-related scanning code in one fell swoop.

So we have three hurdles to overcome:

  1. We need to be able to listen to keyboard strokes no matter which form or control currently has focus.
  2. Since we’re listening to this cacophony of keyboard strokes from all controls in the application, we need to be able to distinguish between strokes that come from the keyboard and strokes that come from the barcode scan gun.
  3. Since it’s conceivable that a control that can’t receive input or shouldn’t receive input might be focused when a barcode is scanned, we need to suppress the Windows messages related to the keyboard strokes generated by the scan gun. (How annoying would it be to hear 12 Windows “ding” sounds upon scanning a barcode, or how annoying would it be to have a UPC show up in that e-mail reply you were typing to a customer when you scanned it look up inventory?)

Our ideal high-level overview would something like this:

Easier said than done.

Easier said than done.

So let’s take a stab at this.

Serial emulation mode?

Some barcode scanners, in addition to supporting USB HID information mode in which they appear as a barcode scanner, also support a serial port emulation mode. In this case, we would communicate with the scanner by sending and receiving commands through the SerialPort class as if it were any other serial device, and you usually tell the scanner to go into this mode by scanning a special “configuration barcode” that its firmware recognizes, found in the owner’s manual. This would be great if

  • the scanner supported such a serial emulation mode;
  • the scanner was meant to be used by our application and our application alone; and
  • we didn’t want the scanner to generate keystrokes anywhere in the operating system.

Unfortunately, not all of our scanners at work support this mode, and even if they did, the scanner is intended to be used by multiple applications (such as FedEx Ship Manager, which requires it to operate as a keyboard wedge). So it seems like the easy solution is out.

Two steps forward, one step back

The first thing that we need to do is to figure out how to get access to the keystroke information no matter which form or control has focus. There are two ways to go about doing this: one is to use the Raw Input API and the other is to use low-level keyboard hook.

But since we also need to know which device the keyboard stroke came from, it looks like the Raw Input API will be the winner; the KBDLLHOOKSTRUCT structure that’s provided by SetWindowsHookEx() doesn’t tell us any device information. So let’s put keyboard hooks on the back burner for now and learn about the Raw Input API.

Diddling around with the Raw Input API

By default, no applications in Windows receive raw input. You have to register for it. And when you’ve registered an hwnd to receive raw input, that hwnd will start getting WM_INPUT messages pumped to it. The WM_INPUT message contains a RAWINPUTHEADER structure that can be passed to various functions in the Raw Input API that can tell you scads of information about the input event that just occurred. What’s important to note is that, with the appropriate flags, these WM_INPUT messages get sent to the hwnd that you register with the API for every input event regardless of whether or not your hwnd currently has focus. This satisfies our first requirement of needing to be able to see incoming keyboard stroke events regardless of whether or not some stupid textbox has focus. The regular device-independent input events like WM_CHAR and WM_KEYDOWN will still get generated for the hwnd; all you’re saying is that “hey, I want to hear about WM_INPUT and get all the gory details, too.”

Using the Raw Input API itself is kind of weird, and the mystical incantations of P/Invoke only make it weirder. This article on CodeProject helped me a lot in this regard, but I still had to drudge through the MSDN documentation and, of course, pinvoke.net.

Time to get started on BarcodeScannerListener. Since we’ll be piggybacking on an hwnd to receive the WM_INPUT messages, we might as well use one that’s going to be around for the lifetime of our application. In this case, this means my main form. But it’d be nice to design this as an independent class so that any consumers don’t need to know about the MainForm. What do you do when you need to override a WndProc without touching the class itself? You got it, it’s NativeWindow to the rescue again.

    public class BarcodeScannerListener : NativeWindow
    {
        /// <summary>
        /// Initializes a new instance of the BarcodeScannerListener
        /// class. The raw input devices that this class will listen to are
        /// registered with the given window handle.
        /// </summary>
        /// <param name="form">the form that should listen for
        /// barcode scans</param>
        /// <exception cref="ArgumentNullException">if the form is null</exception>
        /// <exception cref="ApplicationException">if we are unable to register
        /// for raw input devices</exception>
        /// <exception cref="ConfigurationErrorsException">if an error occurs
        /// during configuration</exception>
        public BarcodeScannerListener(Form form)
        {
            IntPtr hwnd;
 
            if (form == null)
            {
                throw new ArgumentNullException("form");
            }
 
            hwnd = form.Handle;
 
            HookRawInput(hwnd); // We'll take a look at this in a minute
            this.HookHandleEvents(form);
 
            this.AssignHandle(hwnd);
        }
 
        /// <summary>
        /// Hooks into the form's HandleCreated and HandleDestoryed events
        /// to ensure that we start and stop listening at appropriate times.
        /// </summary>
        /// <param name="form">the form to listen to</param>
        private void HookHandleEvents(Form form)
        {
            form.HandleCreated += this.OnHandleCreated;
            form.HandleDestroyed += this.OnHandleDestroyed;
        }
 
        /// <summary>
        /// When the form's handle is created, let's hook into it so we can see
        /// the WM_INPUT event.
        /// </summary>
        /// <param name="sender">the form whose handle was created</param>
        /// <param name="e">the event arguments</param>
        private void OnHandleCreated(object sender, EventArgs e)
        {
            this.AssignHandle(((Form)sender).Handle);
        }
 
        /// <summary>
        /// When the form's handle is destroyed, let's unhook from it so we stop
        /// listening and allow the OS to free up its resources.
        /// </summary>
        /// <param name="sender">the form whose handle was destroyed</param>
        /// <param name="e">the event arguments</param>
        private void OnHandleDestroyed(object sender, EventArgs e)
        {
            this.ReleaseHandle();
        }
    }

Most of the code above is just the kind of bullcrap that we need to do to make sure that we release resources properly when the form’s hwnd gets destroyed. The real meat we want to figure out is that HookRawInput() function in the constructor. This is what does the dirty work of registering our hwnd with the Raw Input API:

/// <summary>
/// Registers ourselves to listen to raw input from keyboard-like devices.
/// </summary>
/// <param name="hwnd">the handle of the form that will receive the raw
/// input messages</param>
/// <exception cref="InvalidOperationException">if the call to register with the
/// raw input API fails for some reason</exception>
private static void HookRawInput(IntPtr hwnd)
{
	NativeMethods.RAWINPUTDEVICE[] rid;
 
	rid = new NativeMethods.RAWINPUTDEVICE[1];
 
	rid[0].usUsagePage = 0x01;      // USB HID Generic Desktop Page
	rid[0].usUsage = 0x06;          // Keyboard Usage ID
	rid[0].dwFlags = NativeMethods.RawInputDeviceFlags.RIDEV_INPUTSINK;
	rid[0].hwndTarget = hwnd;
 
	if (!NativeMethods.RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0])))
	{
		InvalidOperationException e;
 
		e = new InvalidOperationException(
			"The barcode scanner listener could not register for raw input devices.",
			new Win32Exception());
		throw e;
	}
}

Let’s stop for a minute and take a look at what the hell this is doing. The goal here is to P/Invoke the Win32 method called RegisterRawInputDevices(). This takes a variable length array of RAWINPUTDEVICE structures as a parameter. These structures tell us what classes of devices that we want to receive WM_INPUT messages for. Note that we can’t ask for a particular device, and this is what makes things so interestingly complicated–we’re going to get all of the notifications for all keyboard-like devices and we’re going to have to filter out the ones from the barcode scan gun ourselves. But that comes much later.

So what we do here is register ourselves with one class of devices, those devices that are keyboard-like. (Unfortunately, there is no HID usage page for barcode scan guns yet.) The parameters in usUsagePage and usUsage are magic numbers. There is a whole slew of these magic numbers on the USB consortium’s Web site. Since all of desktop scan guns act as keyboard wedges, I went with the usage page and usage (really, could they have chosen terms that were any more confusingly similar?) for a keyboard device and it just worked.

The RIDEV_INPUTSINK flag is what tells Windows to send us WM_INPUT messages regardless of the hwnd that they’re being directed to. This means that even if our main form is minimized and the user has, say, Notepad focused and scans a barcode, we’ll still see the event. I’m not sure if that’s really cool or really spooky.

The actual extern declaration is sitting in a class called NativeMethods. The declaration really isn’t all that interesting and if you want to look at it, you can take a look at the sample code.

Great! So now we’re all set up to get WM_INPUT messages. Let’s check this by actually implementing our version of WndProc in our BarcodeScannerListener class:

/// <summary>
/// Hook into the form's WndProc message. We listen for WM_INPUT and do
/// special processing on the raw data.
/// </summary>
/// <param name="m">the message</param>
[SecurityPermission(
   SecurityAction.LinkDemand,
   Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
	switch (m.Msg)
	{
		case NativeMethods.WM_INPUT:
			this.ProcessRawInputMessage(m.LParam);
			// There's more work to do here, but we'll get to that in a minute
			break;
	}
 
	base.WndProc(ref m);
}

So, this is pretty simple. If we get a WM_INPUT, we call our ProcessRawInputMessage() function on it. Otherwise, we don’t really care about the message. So let’s take a look at that beast of a function. Get your scroll wheel finger ready because it’s a doozy:

/// <summary>
/// Process the given WM_INPUT message.
/// </summary>
/// <param name="rawInputHeader">the rawInputHeader of the message</param>
/// <returns>whether or not the keystroke was handled</returns>
private bool ProcessRawInputMessage(IntPtr rawInputHeader)
{
	bool handled;
	uint size;
 
	handled = false;
	size = 0;
 
	// First we call GetRawInputData() to set the value of size, which
	// we will the nuse to allocate the appropriate amount of memory in
	// the buffer.
	if (NativeMethods.GetRawInputData(
			rawInputHeader,
			NativeMethods.RawInputCommandFlag.RID_INPUT,
			IntPtr.Zero,
			ref size,
			(uint)Marshal.SizeOf(typeof(NativeMethods.RAWINPUTHEADER))) == 0)
	{
		IntPtr buffer;
		BarcodeScannerDeviceInfo deviceInfo; // I'll get to this later
		NativeMethods.RAWINPUT raw;
 
		buffer = Marshal.AllocHGlobal((int)size);
 
		try
		{
			if (NativeMethods.GetRawInputData(
					rawInputHeader,
					NativeMethods.RawInputCommandFlag.RID_INPUT,
					buffer,
					ref size,
					(uint)Marshal.SizeOf(typeof(NativeMethods.RAWINPUTHEADER))) == size)
			{
				raw = (NativeMethods.RAWINPUT)Marshal.PtrToStructure(buffer, typeof(NativeMethods.RAWINPUT));
 
				// This is what filters out for the right device we're looking for.
				// How'd I get that hDevice magic number? Keep reading.
				if (this.devices.TryGetValue(raw.header.hDevice, out deviceInfo))
				{
					handled = true;
 
					if (raw.header.dwType == NativeMethods.RawInputType.RIM_TYPEKEYBOARD)
					{
						if (raw.keyboard.Message == NativeMethods.WM_KEYDOWN)
						{
							StringBuilder localBuffer;
							byte[] state;
 
							localBuffer = new StringBuilder();
							state = new byte[256];
 
							if (NativeMethods.GetKeyboardState(state))
							{
								if (NativeMethods.ToUnicode(
										raw.keyboard.VKey,
										raw.keyboard.MakeCode,
										state,
										localBuffer,
										64,
										0) > 0)
								{
									if (localBuffer.Length == 1 && localBuffer[0] == 0x4)
									{
										this.FireBarcodeScanned(deviceInfo);
									}
									else
									{
										this.keystrokeBuffer.Append(localBuffer.ToString());
									}
								}
							}
						}
					}
				}
			}
		}
		finally
		{
			Marshal.FreeHGlobal(buffer);
		}
	}
 
	return handled;
}

After working with Java and C# for a few years, this kind of API is a reminder of how boring and tedious manual memory management can be. To get details about the WM_INPUT message, including important things like the device it’s coming from, we need to call a method in the Win32 API called GetRawInputHeader(). Since the size of the data can vary, we have to call the method once passing a null reference to a buffer (IntPtr.Zero) and it will populate the size parameter for us. Then we can allocate memory for a buffer of that size and call the function again. Then we marshal the data in that buffer to a RAWINPUT struct, which is the bad boy that tells us what device the keyboard stroke is originating from.

The rest of the method is now jumping ahead: if the device handle (hDevice) is one that we’re watching for (namely, the device handle of the barcode scan gun) and the message is a WM_KEYDOWN event, then we get the current keyboard state and call ToUnicode() to convert the current “keyboard” state into an actual usable character. If a character is returned, we’ll add it to a StringBuilder called keystrokeBuffer. Since all of our scan guns are configured to send an EOT character (ASCII 0×4) at the end of a barcode, we’ll watch for that and if we see it we’ll clear out our buffer and fire the BarcodeScanned event.

Why go to the trouble of GetKeyboardState() and ToUnicode()? Well, remember that the barcode scan gun really is just simulating a keyboard. So when it tries to send our EOT character at the end of the barcode, it doesn’t actually press an EOT key–there’s no such key on your keyboard. Instead it presses Control and then it presses D. These two keyboard strokes get sent in two different WM_INPUTs and two different calls to this method. If we’d been just looking at the virtual keycode on each method call, we’d end up with a lot of bogus characters. Let’s let ToUnicode() do the hard work of figuring out whether a letter is lowercase or uppercase, or if it’s trying to output a $ instead of a 3.

Blocking the keyboard strokes

So our third requirement was to block the keyboard strokes from actually reaching the control if they originated from our scan gun. We might be tempted to revisit our old friend the low-level keyboard hook for this. Indeed, we might spend three hours pursuing this option only to realize something quite unfortunate: the low-level keyboard hook, which provides no device-specific information, runs before any WM_INPUT messages get sent to us by the Raw Input API. That means that by the time that we have enough information to decide whether or not we want to swallow the keyboard stroke, it’s already too late–we’ve missed our chance to swallow it because the keyboard hook callback is long gone.

A less elegant, possibly race-condition prone condition is to just zap all of the WM_KEYDOWN events in the WndProc method if we handled the keyboard stroke:

protected override void WndProc(ref Message m)
{
	switch (m.Msg)
	{
		case NativeMethods.WM_INPUT:
			if (this.ProcessRawInputMessage(m.LParam))
			{
				// This is the new stuff
				NativeMethods.MSG message;
				NativeMethods.PeekMessage(
					out message,
					IntPtr.Zero,
					NativeMethods.WM_KEYDOWN,
					NativeMethods.WM_KEYDOWN,
					NativeMethods.PeekMessageRemoveFlag.PM_REMOVE);
			}
 
			break;
	}
 
	base.WndProc(ref m);
}

We P/Invoke a call to PeekMessage() with a parameter of PM_REMOVE to do this. By passing in a null pointer as the hwnd parameter, we will zap all of the WM_KEYDOWN messages for handles that are running on the current thread. Since all of app’s UI is running in a single-thread, we can be sure we’re zapping the events regardless of which of our controls had focus. This seems to work well enough, especially as I can’t think of a scenario where a user would be typing on the keyboard and scanning a barcode at the same time. But I can envision a scenario where we try to clear the WM_KEYDOWN but it hasn’t be posted yet, allowing a stray character to get through. I haven’t seen it in practice, but it’s something to keep in mind.

Figuring out the device handle

So the last little bit is to figure out the device handle of a barcode scan gun. This is so that we can compare it against the hDevice handle that comes back in the RAWINPUT structure in the Raw Input API. To our constructor we’ll add a method invocation for InitializeBarcodeScannerDeviceHandles() and define that function thusly:

/// <summary>
/// Enumerates devices provided by GetRawInputDeviceList. We'll only listen
/// to these devices.
/// </summary>
/// <exception cref="ConfigurationErrorsException">if an error occurs
/// during configuration</exception>
private void InitializeBarcodeScannerDeviceHandles()
{
	BarcodeScannerListenerConfigurationSection config;
	BarcodeScannerListenerConfigurationElementCollection hardwareIdsConfig;
	List<string> hardwareIds;
	uint numDevices;
	uint size;
 
	config = BarcodeScannerListenerConfigurationSection.GetConfiguration();
	hardwareIdsConfig = config.HardwareIds;
	hardwareIds = new List<string>();
	numDevices = 0;
	size = (uint)Marshal.SizeOf(typeof(NativeMethods.RAWINPUTDEVICELIST));
 
	foreach (BarcodeScannerListenerConfigurationElement hardwareId in hardwareIdsConfig)
	{
		hardwareIds.Add(hardwareId.Id);
	}
 
	// First, we get the number of raw input devices in the list by passing
	// in IntPtr.Zero. Then we allocate sufficient memory and retrieve the
	// entire list.
	if (NativeMethods.GetRawInputDeviceList(IntPtr.Zero, ref numDevices, size) == 0)
	{
		IntPtr rawInputDeviceList;
 
		rawInputDeviceList = Marshal.AllocHGlobal((int)(size * numDevices));
		if (NativeMethods.GetRawInputDeviceList(
			rawInputDeviceList,
			ref numDevices,
			size) != uint.MaxValue)
		{
			// Next, we iterate through the list, discarding undesired items
			// and retrieving further information on the barcode scanner devices
			for (int i = 0; i < numDevices; ++i)
			{
				uint pcbSize;
				NativeMethods.RAWINPUTDEVICELIST rid;
 
				pcbSize = 0;
				rid = (NativeMethods.RAWINPUTDEVICELIST)Marshal.PtrToStructure(
					new IntPtr((rawInputDeviceList.ToInt32() + (size * i))),
					typeof(NativeMethods.RAWINPUTDEVICELIST));
 
				if (NativeMethods.GetRawInputDeviceInfo(
					rid.hDevice,
					NativeMethods.RawInputDeviceInfoCommand.RIDI_DEVICENAME,
					IntPtr.Zero,
					ref pcbSize) >= 0)
				{
					if (pcbSize > 0)
					{
						string deviceName;
						string friendlyName;
						BarcodeScannerDeviceInfo info;
						IntPtr data;
 
						data = Marshal.AllocHGlobal((int)pcbSize);
						if (NativeMethods.GetRawInputDeviceInfo(
							rid.hDevice,
							NativeMethods.RawInputDeviceInfoCommand.RIDI_DEVICENAME,
							data,
							ref pcbSize) >= 0)
						{
							deviceName = (string)Marshal.PtrToStringAnsi(data);
 
							if ((from hardwareId in hardwareIds
								 where deviceName.Contains(hardwareId)
								 select hardwareId).Count() > 0)
							{
								friendlyName = GetDeviceFriendlyName(deviceName);
 
								info = new BarcodeScannerDeviceInfo(
									deviceName,
									GetBarcodeScannerDeviceType(rid.dwType),
									rid.hDevice,
									friendlyName);
 
								this.devices.Add(rid.hDevice, info);
							}
						}
 
						Marshal.FreeHGlobal(data);
					}
				}
			}
		}
 
		Marshal.FreeHGlobal(rawInputDeviceList);
	}
}

This mess of interop code reads our configuration file for a list of hardware IDs to look for. For example, one of the strings I’m looking for in the device name is HID#Vid_05e0&Pid_028a, which I got from Device Manager, and this is enough to identify our Hand Held scan gun. Then we call GetRawInputDeviceList() (twice, once to get the size of the buffer that we need to allocate, and once again to actually fill that buffer once we’ve allocated it) to get a list of the devices that we’re actually listening to. For each device, a call to GetRawInputDeviceInfo() gets us the device name, which is this really horrific looking string, but my hardware ID is in there somewhere. So if I have a match, I grab some information about the device, wrap it up in a simple BarcodeScannerDeviceInfo object, and add the device handle and this struct to a dictionary called devices. Our ProcessRawInputMessage() function can now look at this dictionary to determine which WM_INPUT messages to listen to and which ones to ignore.

Now, you may be thinking, why do all that to get the device handle? Why not just store that in your config file? Well, the problem with USB devices is that device handle changes every time you unplug and replug the barcode scan gun. The hardware ID is the only reliable identifier. I don’t understand what most of the huge device name string actually contains, but at this point, I’m not sure if I really care to become a USB expert–right now, things Simply Work, and I’m inclined to leave them that way.

Putting it all together

With all this in place, I can run the app, scan the UPC symbol of the ridiculously American-sized Diet Mountain Dew sitting on my desk, and squeal for joy as (A) the textbox does NOT show any characters, (B) the status bar listens to the BarcodeScanned event and displays the UPC data, and (C) I type on the keyboard and data is correctly passed through to the textbox and ignored by the BarcodeScannerListener. If I scan the barcode in another application, my application still sees it, but the application still gets the text passed through–that’s not a big deal for me. (The reason for this is our call to PeekMessage() only zaps messages for my current application thread, not for the entire OS.)

I’ll clean up the code and see if I can post something up soon. And if you know of a way where this could have been done in three lines, by all means, let me know.

At the very least, it’s nice to scan away on those huge inventory shipments and not worry about some stupid textbox having focus.

Update: I’ve put together a bare-bones version of the code. Sample Application Code

Update 5/15/2010: One Year Later

So it’s been about 14 months since I put the above code into production in my application. Thanks to some of the helpful comments passers-by have left, and thanks to some rare crash reports that I was able to debug, I’ve made some changes to the code that I use in production and would like to make them known, to save you some headaches.

PeekMessage() was a bad idea

The first is that I removed the call to PeekMessage() and instead used an IMessageFilter implementation. The reason that PeekMessage() was problematic is that it removed all of the WM_KEYDOWN messages in the window’s message queue.

Under normal conditions, this worked just fine, since there was normally only one WM_INPUT (the one being processed) and one WM_KEYDOWN (the one that corresponds to the WM_INPUT message) in the queue. But if the system was “busy” (say, for example, you start up FedEx Ship Manager in the background and scan something), then some messages–particularly, the SHIFT key, as noted in the comments below–would be “missed.” That’s because the tax on OS resources would slow down the rate at which the application could process messages while the barcode scanner continues to dish out messages at a constant rate.

So what would happen is that, say, three WM_KEYDOWN messages would appear on the queue: let’s use “b”, SHIFT, and “c” as an example set. By the time the application got around to processing the first WM_INPUT (the one for the “b” keystroke), it would call PeekMessage() and inadvertently zap all three WM_KEYDOWN messages.

And normally even that wouldn’t be a big deal, because we’re looking at WM_INPUT messages, after all, not WM_KEYDOWN messages, to determine what to put in our StringBuilder. But note that we call GetKeyboardState() to determine the state of the keyboard and pass that byte array into the ToUnicode() call to get the actual character back. It turns out that GetKeyboardState() works by examining the WM_KEYDOWN messages that are sitting in the message queue–and guess what, we zapped the SHIFT keypress right out of the queue by calling PeekMessage(). As a result, we’ll fill our StringBuilder with “bc” instead of “bC”, and we might be left scratching our heads as to why the SHIFT, CTRL, or ALT keys aren’t always “making it through.”

So my workaround is simple:

    /// <summary>
    /// Filters WM_KEYDOWN messages.
    /// </summary>
    public class BarcodeScannerKeyDownMessageFilter : IMessageFilter
    {
        /// <summary>
        /// Gets or sets a value indicating whether or not the next keydown message
        /// should be filtered.
        /// </summary>
        public bool FilterNext
        {
            get;
            set;
        }
 
        /// <summary>
        /// Filters out a message before it is dispatched.
        /// </summary>
        /// <param name="m">The message to be dispatched. You cannot modify
        /// this message.</param>
        /// <returns>
        /// true to filter the message and stop it from being dispatched; false
        /// to allow the message to continue to the next filter or control.
        /// </returns>
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public bool PreFilterMessage(ref Message m)
        {
            bool filter = false;
 
            if (this.FilterNext && m.Msg == NativeMethods.WM_KEYDOWN)
            {
                filter = true;
                this.FilterNext = false;
            }
 
            return filter;
        }
    }

If the FilterNext property is set, then we filter out the next WM_KEYDOWN that we see and then set the property back to false. Otherwise, we let the message through.

The BarcodeScannerListener now instances the BarcodeScannerKeyDownMessageFilter (what a mouthful) in its constructor and registers it with the Windows Forms-provided Application class:

            this.filter = new BarcodeScannerKeyDownMessageFilter();
            Application.AddMessageFilter(this.filter);

And the WndProc message sets the FilterNext property of the filter as it sees appropriate:

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case NativeMethods.WM_INPUT:
                    if (this.ProcessRawInputMessage(m.LParam))
                    {
                        this.filter.FilterNext = true;
                    }
 
                    break;
            }
 
            base.WndProc(ref m);
        }

This has proven to be much more reliable in practice than the old PeekMessage() method. I haven’t had problems with “missed keystrokes” since.

GetKeyboardState() only works as expected when you have focus

By design, Windows keyboard messages go straight to the window that has focus. When I originally wrote the article, I had the HookRawInput() method of the BarcodeScannerListener specify RIDEV_INPUTSINK. This allowed me to receive WM_INPUT messages even when my application did not have focus.

Well, that meant I still received the WM_INPUT messages, but I didn’t receive the WM_KEYDOWN messages. And normally I wouldn’t care about that, but that also means that I wasn’t receiving WM_KEYDOWN messages for things like SHIFT, CTRL and ALT. The net result? Barcodes would be scanned with intended case if the application had focus, but they would be scanned as all lowercase if the application did not have focus. That’s because GetKeyboardState() assesses the keyboard state by looking at the WM_KEY* messages in the message queue, as I mentioned above in the discussion about the problems with the PeekMessage() call.

I didn’t come up with a workaround for this other than to say that I now only support scans when the application has focus. As a result, I used 0 instead of specifying any flags in HookRawInput().

(Thanks to commenter Matt for pointing this out.)

A rare memory corruption bug caused great hair loss

If there’s one thing that I hate, it’s bugs that I fix but never truly understood the original cause. And on this one I’m not alone.

Every once in 10,000 or so scans, the application would crash with a memory corruption error in msvcr80.dll, and it always occurred when marshalling data into the RAWINPUT structure in the ProcessRawInputMessage() function of the BarcodeScannerListener:

raw = (NativeMethods.RAWINPUT)Marshal.PtrToStructure(buffer, typeof(NativeMethods.RAWINPUT));

(DrkNess, one of the commenters on this article, also encountered the error.)

Now, as we know with access violations, the memory corruption could have occurred at some other point in the program: this is just an unmanaged call that gets called exceptionally frequently and so is likely to stumble across the corrupted memory boundary.

I read all up on pinning memory with the garbage collector (shouldn’t have applied), double- and triple-checked the P/Invoke declarations (they seemed to be correct), and even found several references to a similar problem in the article on CodeProject that became an inspiration for this one, but damned if I couldn’t find a reason for the error. Obviously I had screwed something up in a subtle way that is fantastically hard to reproduce.

So I ripped out all of the P/Invoke declarations and created a C++/CLI assembly that contained one class, the help-me-I’m-running-out-of-names-for-these-things BarcodeScannerListenerInteropHelper. Its sole purpose is to be used by the BarcodeScannerListener and bridge the gap between the managed world and the unmanaged Windows platform calls without the need for P/Invoke. With P/Invoke out of the way, so too has the memory corruption bug disappeared. A nice side effect is that the BarcodeScannerListener class has become much smaller and easier to understand.

For the really hardcore, write an upper device driver filter

Throughout this process I also learned that one sure-fire way to implement all of this barcode scanning functionality is to write an upper device driver filter. But I still stick to my method because (a) it works well enough, (b) doesn’t require special configuration on the client machine, and (c) is a hell of a lot easier than mucking with drivers.

Such a filter would enable us to receive input regardless of which application had focus, and it would enable us to control which applications received the input, but it does look like it would be a lot of work.

New Conclusions and Delusions

The code has held up pretty well, and I’m glad that I finally found the time to write a post-mortem analysis of the issues that I’ve encountered.

Here’s an updated version of the sample application that incorporates the changes that I’ve made. Good luck!

99 thoughts on “Distinguishing Barcode Scanners from the Keyboard in WinForms

  1. The sample application code that you have provided generates error after error after error. Bare boned or not but even after an hour of work I still can’t get this to build…

    Is this really the most up to date version that you have right now?

  2. Well it is the usual list of not filled in methods. None of the get and set methods had any code connected to them but the most annoying mistake that i am not sure how to fix is i nthe code bit: “”if ((from hardwareId in hardwareIds where deviceName.Contains(hardwareId) select hardwareId).Count() > 0)”"

    this is as far as i can tell not a correct C# syntax but i also am unable to see what exactly this piece of code it supposed to do. I checked the code with what you wrote above and in that article the same code appears. It looks a lot like some form of SQL statement but i can not be sure about that.

    • That is not a bug nor incorrect syntax. That is a LINQ expression and is a new feature of the .NET Framework 3.5.

      If you are trying to use an older compiler, you will have to recast that expression to a simple for loop.

      It just provides a quick way of saying “select the number of hardwareIds where the deviceName contains part of any given hardwareId.”

      Additionally, the .NET Framework 3.5 provides a shorthand syntax for defining properties that have simple getters and setters. It’s called auto-implemented properties because the compiler will automatically create a backing store variable for you, saving some typing.

      As such, you will need to either upgrade to the .NET Framework 3.5 or port the code as you have described. Hope that helps.

  3. ok i got the code to build after getting my hands on visual studio 2k8. the only thing now that is not yet included in the sample code is an actual useable windows form but that is easy enough to create. thnx for putting up with me.

  4. hmm i still seem to have 1 last problem. everything is fine. i add a tekst box to the form and it won’t register anything beeing scanned. on the other side however i also do not get a popup with what i DID scan.

    it looks like my OnBarcodeScanned event is never fired? am i missing something? i only changed the deviceID in de config and the rest is just your basic application.

    • So the whole point of the article is to not need a textbox. If you want to use a textbox, then you don’t need to use any of the code here because Windows will just treat the barcode scanner as a keyboard. You would just plop a textbox down and scan something when it has focus. This is why the sample includes a blank Windows Form; all you have to do is scan a barcode and get a popup window with the scanned barcode. If you add a textbox, the textbox will not receive the barcode, and this is by design. (Alternatively, you could remove the PeekMessage() call in the BarcodeScannerListener’s WndProc() if you wanted to undo the keystroke-swallowing behavior.)

      All of our barcode scanners terminate their transmissions with an EOT character, ASCII 0×4. You can see that in the BarcodeScannerListener’s ProcessRawInputMethod() method it checks for a EOT character and, if it sees it, triggers the BarcodeScanned event with the data that is currently in the keystrokeBuffer.

      You can typically configure a barcode scanner to send a custom suffix such as EOT after every scan by scanning special configuration barcodes in the back of your barcode scanner’s user manual.

      If you can’t or don’t want to make it send an EOT suffix character, you’ll have to modify the appropriate lines in the ProcessRawInputMessage() function to use some other algorithm for determining when to fire the event: perhaps all of the barcodes you’re looking for are of a particular length, or perhaps you could devise a regular expression to match against the incoming input.

      Hope that helps.

  5. It seemed as if there were some other problems but in the end it was just a strange little habit of the scanner. i reconfigured it and now everything works peachy

    thnx for all the help

  6. This worked wonderfully. This was exactly what I was looking for. I hate messing around with windows API’s, but this actually made a little more since.

    Thanks for the post. –Joe

  7. Hi there, this worked wonderfully for me… However i would like to ask, isit possible to only display the information when the intended form is active? Coz currently i display the captured data in a label on my form, and the form will display barcode scanned outside the form. thanks.

    • Hmm, if you’re using my sample, I reckon that you form is listening to that BarcodeScanned event. In your event handler, you could check to see if this == Form.ActiveForm; if it does, then you update your label, and if it isn’t, then you just don’t do anything with the event. I haven’t tried it, but I bet something like that would work.

      • HI i installed vs2008 on xp sp2,but OnBarcodeScanned event is not firing,even im not getting any error,but i run the application igot one pop Project out of Date.. Please can one help me out…..

  8. Hello again,

    After using the application for a while I have to say that it is exactly what i was looking for. I have however 1 problem that keeps returning now.

    I am running the application on a normal PC so there are also other things happening on the system.

    After a while (say 2 hours average) i keep getting a stack overflow exception from a part of the input processor.

    I edited the code a bit (removing white lines) so it might not be the same code line but for me the overflow happens in de BarcodeScannerListener.cs on line 470 in de line :

    raw = (NativeMethods.RAWINPUT)Marshal.PtrToStructure(buffer, typeof(NativeMethods.RAWINPUT));

    i already tried enlarging the buffer but that just prolongs the time till the overflow happens.

    please help me with this

    thank you in advance

  9. Sounds like I’ve got a bug related to freeing an unmanaged resource. I’ll leave it running on my workstation today and see if I can recreate the issue.

    I resolved the issue and discuss it in the 5/15/2010 update at the end of the article. It was indeed a problem related to marshalling unmanaged data, but I’ll be damned if I know what I screwed up. I fixed the problem by avoiding P/Invoke entirely.

  10. In line 354 (the LINQ expression); if you change deviceName.Contains(hardwareId) to deviceName.IndexOf(hardwareId, StringComparison.InvariantCultureIgnoreCase) >= 0 you won’t have to worry about getting the case right for the vid and pid values in the config value. I have a habit of using uppercase for hex values and this way it will guarantee a match even if it is stored in lowercase.

  11. Any idea why NativeMethods.ToUnicode would give different results based on whether the sample application has focus rather than say…Notepad?

    %b4024720000000007^FDMSTEsTCARD^130410123456789? ;4024720000000007=1304101234%^&*(?

    vs

    %B4024720000000007^FDMSTESTCARD^130410123456789? ;4024720000000007=130410123456789?

    Looks conceptually like a Shift key flickering on and off.

    • Notepad could be interpreting some commands as control characters. For example, sending ASCII EOT will cause Internet Explorer to toss up the “Add Favorite” dialog because it interprets as CTRL+D.

      This is because GetKeyboardState() doesn’t work as intended if the application does not have focus. I’ve updated the article to talk about this in the 5/15/2010 update.

  12. The quirk of it is that I can give any other program focus and swipe the card (I’m using this with a card swiper) and it works fine. Did it on accident in Visual Studio when debugging a few times. Did it once in an IM, did it in multiple text editors, and to IE. I went ahead and used this with a barcode scanner and it works fine, no issues.

    I can’t really blame it on the code, it works fine with the barcode reader. I want to blame it on the card swiper, but it’s working fine everywhere else.

    Was just checking if you had any guesses offhand.

    • Oh! Like a Cherry keyboard with a swiper? IIRC the last time I dealt with one of those, it actually WAS pressing its little SHIFT key to get keys into a current state. It was actually emulating a keyboard, so to get “T” it would send “SHIFT” followed by a “T” keystroke.

      Are you remembering to call GetKeyboardState() and pass that into the ToUnicode() call? I wouldn’t be surprised if I borked something up there.

  13. No, you did that fine. That’s part of the quirkiness of the thing. It doesn’t consistently shift the case on the characters. I can swipe the same card ten times and get ten different results. Each character can be shifted wrong independently.

    But again, if any other program has focus, it works fine. And the barcode scanner works fine (probably because it never uses shift).

    • Just a wild guess….

      Remembering in WndProc where I added the PeekMessage() call to prevent the keystrokes from actually reaching the intended window? Try commenting that out and running it. I’ve always felt uneasy about that call, thinking there’s got to be a better way to do it, but I’m not sure what to use. (You might get a lot of ding sounds depending on what has focus….)

      While PeekMessage() indeed turned out to be problematic, it wasn’t the cause of Matt’s issue. I discuss this and the resolution in the 5/15/2010 update at the end of the article.

  14. Yeah, that made the difference it appears. Does that mean it tracks keyboard state based on the windows messages and the peek/remove is screwing with its method of tracking the state?

  15. I tried not calling base.WndProc(ref m); after any message that comes from the specific hardware handle. It seems to do what I want, yet “enter key” presses still make it through somehow.

  16. Thank you for the great article and the code. It helped me a lot and works very well.

    However, one scenario… During the barcode scan, if another application like Word or Excel has the focus, the barcode read gets typed into that application. My app gets the barcode as well, but how can I stop it from going to other app which is on focus?

    I want just my app to get that info, but not any other app regardless of which is having focus during the scan.

    I have written this in framework 2.0. Any help is greatly appreciated.

    • Anita:

      I can’t think off the top of my head how we’d do that, unless it was with a keyboard hook. The problem with a keyboard hook, as mentioned in the article, is that it doesn’t provide information about which device the keystroke came from. The raw input API provides that, but the WM_INPUT messages are received after the keyboard hooks are fired, so that negates us setting some boolean flag like “barcode input coming in”. And indeed, even the existing code of using PeekMessage to zap the character doesn’t work very exceedingly well; as alluded to in the above comments, once in a while it’ll zap too many characters if the application ever falls behind on processing the WM_INPUT messages. I’ve been meaning to revisit that particular section of the code for a while, but darn it if I’m stumped as to how to go about it.

      If you or anyone else has any suggestions on the matter, I’d love to hear them. Sorry that I can’t be of more help for now.

  17. Hi Nicholas,

    Great code – thank you very much for posting it. Do you have any issue with anyone including some snippets in commercial software? If so, no worries, I’ll rewrite the applicable parts… Just wanted to check first to make sure I use any snippet appropriately!

    Regards, Brett

    PS I’ll gladly post back my variation if you want… basically changed it so that the class is instantiated once for each device — with the class taking the hardware info and delimiter as parameters — so -in my case- I’ve got barcode scanners and magstripe readers — that way the barcode, magstripe and etc. get their own events and delimiters.

    • @Brett

      I don’t give two hoots; consider it public domain (anything else on the blog for that matter).

      As addressed in the comments, in my little app at work, once in a blue moon, the code will “miss” the EOT character that our barcode reader sends. I’m not sure what causes this, but I think my shenanigans with suppressing the keyboard input from reaching the form is the culprit. I haven’t designed a workaround and it has been low on my list of priorities. Caveat emptor!

      (Edit: It occurs to me now that zapping WM_KEYDOWN is probably fine but listening for WM_KEYUP would do the trick. That would prevent most controls from seeing the input, but I could still react to the key up event. Hmm, total hack, but I’ll have to try that.)

      I discuss the workaround for this issue in the 5/15/2010 update.

  18. Hi Nicholas,

    Thanks a lot for the code, it works very well in my windows forms application.

    But now I have to migrate my application to WPF Applcation, and i had a problem when using BarcodeScannerListener class. The constructor of this class is need a System.Windows.Forms.Form. Unfortunately, the WPF Application use System.Windows.Window.

    Do you have any idea about this situation?

    • It really just needs the window’s Handle. Now, I haven’t dealt WPF much at all–it’s one of those things that I really need to work on–but I know that any window used by WPF has got to have an unmanaged Handle. When you find it, you can just modify the BarcodeScannerListener class to pass the handle to the NativeWindow instead of the Form.

  19. I just want to give you my gratefulness for this code and example. That’s exactly what i was looking for and works like a charm.

  20. Hello, Do you recommend a particular scanner? In the $60 – $100 range? I have bar codes on concert tickets that I need be able to scan onto a textbox of a webapge.

  21. I feel this is a very silly question but i am new to this whole scanner stuff, need this for personal use asap, niether me nor my personal programer has the idea to figure this out.

    please tell me how to put my pid and vid in the code supplied (configuration file code: ).

    thanks in advance.

  22. Thank you very much for taking the time to put this excellent article together. It has been both interesting and a lifesaver!

    Cheers,

    Scott

  23. It’s not working.

    I used the pid, vid of my scanner but it does nothing.

    Simply nothing. Tried on Xp, Vista, Win 7.

    Please Help.

  24. @Alex

    Try stepping through InitializeBarcodeScannerDeviceHandles(), particularly around line 353, to see if your barcode scanner is getting added to the list of items to watch for it.

    Additionally, the code looks for an EOT character to determine the end of the barcode and fire the event. If your scanner does not send the EOT character, you’ll need to change ~ line 476 to watch for your sentinel value or buffer length and fire the event.

  25. it seems as if to clear up the funky issue with caps vs. lowercase, a simple delay helps in the WndProc() method:

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case NativeMethods.WM_INPUT:
                    System.Threading.Thread.Sleep(2);
                    this.ProcessRawInputMessage(m.LParam);
                    break;
            }

        base.WndProc(ref m);
    }
    

  26. I have the same problem JUST like Alex.I tried to Debug it by stepping through InitializeBarcodeScannerDeviceHandles(), At line 353 Neither “if ((from hardwareId in hardwareIds where deviceName.Contains(hardwareId) select hardwareId).Count() > 0)” or replace “deviceName.Contains(hardwareId)” to “deviceName.IndexOf(hardwareId, StringComparison.InvariantCultureIgnoreCase) >= 0″ can get TRUE value.so,my barcode scanner could not added to the list of items. I have been modified the app.config file as

    But is dose not work. I used Simple Chinese Vista Home basic edition. thnx.

    • @Ajex

      The correct format would be something like “HID#Vid_05e0&amp;Pid_028a”; different components of Windows seem to display it slightly differently. Note the ‘#’ sign instead of the ‘\’.

  27. @Nicholas Piasecki

    So i used “#” instead of the “\”,it’s works fine at 32Bit OS,but i just tested it can not run correctly Under Win7 64Bit.

  28. You need to give your StringBuilder in ProcessRawInputMessage a capacity (it’s 16 by default), or the call to ToUnicode will crash under .NET 4.0.

    Replace

    localBuffer = new StringBuilder(); with localBuffer = new StringBuilder(64);

    to fix the problem.

  29. Very nicely done! Not quite what I needed, but close enough that with a little work I have what I needed.

    My thanks!

  30. weird, I get no error, but also no message. Looks like the device is recognized, but the OnBarcodeScanned is not fired when scanning a code

  31. I did another test, not with your class on another app, just intercepting the keypress event: well, it looks like if I scan a barcode on a textbox everything’s fine, but when I do it on the form itself it doesn’t get the carriage return from the scanner. I know scanner sends it because if I try it on notepad it shows a new line, so it’s definately there. I think that maybe then the OnBarCodeScanned event doesn’t get fired because the carriage return is not there. Any thoughts on why this would happen? thanks

  32. Hi Nicholas Great article!

    Do you know how to avoid printing of barcode in other windows? In my application I need processing barcode only in the Listener and I would not to show it in other windows (like notepad, word ecc..) Many thanks Dino

  33. This is an awsome program you have come up with, I thank you for all the work you have done. I too was looking for exactly this type of solution, however I dont know c# nor does this code compile in my VS2005 ide :( . So I was painfully trying to port this over to c++. I managed to get it working in c#, but it crashed everytime ProccessRawInputDevice tried to call this.FireBarcodeScanned(deviceInfo);. Maybe this is linked to the once in 10000 crash you were getting from marshalling data?

    anyways, I came back here to read up on how you did a few things as i try to redo everything in c++ and I noticed you updated it very recently. I had a question regarding low level keyboard hooks and RAWINPUT. As far as stoping other application from getting the barcode scans, is it possible to impliment both? since keyboard hooks fire before the RAWINPUT, is it possible to buffer the keyboard hooks and sync them with RAWInputs. For example, you press a key, keyboard hook grabs it, holds onto it untill you proccess the rawinout, and if its from the device you want, go back to the keyboard hook and eat up the event so its not passed onto other forms?

    • @David

      Yeah, the error you were experiencing was probably due to a bad P/Invoke that was resolved in the update that I posted on 5/15/2010. On 64-bit machines it simply did not work and I had been blissfully unaware, but those types of issues seemed to be resolved by moving the P/Invokes to a C++/CLI helper class.

      I targeted .NET 3.5 in Visual Studio 2008, so that’s why you can’t build in 2005. To get it to work in 2005, you’ll just need to translate the LINQ expression in the BarcodeScannerListener and fill in the auto-generated properties (the one with get; set;) since those were both .NET 3.5+ features, and Visual Studio 2005 targets .NET 2.0.

      The problem with the keyboard hook is it fires before raw input is processed. So you have to make the yea/nay call about whether or not to block the keystroke at that time; if you say “no”, then the WM_INPUT message from the raw input API never gets generated, so unfortunately I don’t see a scenario of synchronizing the two panning out.

      I think you may end up having to the upper level filter driver route, but that seems messy.

      Finally, an alternative is to check the capabilities of your barcode scanner. Some scanners, in addition to USB HID emulation mode in which it acts as a keyboard, also support a serial emulation mode. In this case you would communicate with the scanner through the SerialPort (or their unmanaged equivalents). It is a far simpler and less error-prone model, but it also means the scanner would only be used by your application (in my case, the scanner still needed to work on other applications on the machine, such as FedEx Ship Manager, and not all of our barcode scanners supported serial mode to boot). You usually tell the scanner to switch modes by scanning a special configuration barcode in the owner’s manual.

      Hope that helps. Good luck!

  34. Ok, so I looked into this driver filter and came to the conclusion its above my head and current programming ability. I have a thought though. You may know more about the lowlevel keyboard hook than I so ill ask this. Is it possible to intercept one at a time and change to a char that is meaningless, storing the original one, once changed, send that onto the rest of the system with the CallNextKeyboard thing API, then let the system tell you where it came from. If it was not from your scanner, you Repost the message, and if it was from your scanner, you do what you need to in the program? Would this work? Or maybe its to hard to post messages to windows you have no idea where they were originally going?

  35. Hello Nicholas,

    Excellent work on this solution. However, I cannot get this to build without specifying the projects to build for x86. Have you ran into this? If so, how can I get this to build. What triggered me to run this compiled for x86 was the following error:

    Could not load file or assembly ‘BarcodeSample.UI.WinForms.Interop, Version=1.0.3787.26958, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. An attempt was made to load a program with an incorrect format.

    Once I made the BarcodeSample.Model project compile as x86. th program ran, but did not fire the barcode scanned event. My guess is the same reason why other solutions will not run x64 correctly, which has to do with some buffer size being different between x86 and x64.

    If you can be of any help, please let me know. My preferred solution would be to build under Windows 7 x64 / VS 2010.

  36. Hi Nicholas,

    great work you did there.

    I am having exactly the same problem as Ryan, When starting not in x86, the BadImageFormatException as described by Ryan is thrown.

    When compiling for x86 and then starting, the Program runs without any exceptions, and it also adds the HID interfaces from the list in App.config (I stepped through this..), but then no BarcodeScannedEvent will be fired.

    I was testing this in VS2008 under Win 7 x64 – VS2010′s conversion seems to mess the solution up a little, so I skipped this already :-)

    • I probably forgot and left it as ‘AnyCPU’. It should be set to ‘x86′. This will always tell the .NET runtume to JIT into a 32-bit image, even on a 64-bit machine. For the vast majority of LOB applications this is not an issue since we are usually not hitting memory boundaries within a particular process (unless we’re Photoshop, which we aren’t).

      An assembly set to ‘AnyCPU’ means that you get 32-bit code on a 32-bit machine and 64-bit code on a 64-bit machine just in time, automagically. But the C++/CLI assembly is partially already compiled (we’re working with Win32 headers, after all, and they’re in C/C++) against 32-bit code. So on a 32-bit machine, ‘AnyCPU’ lucks out and we are okay, but on a 64-bit machine, we get 64-bit JITted assemblies trying to talk to 32-bit C functions, and we end up with an error.

      The easiest solution, as I mentioned, is to just use ‘x86′, understand the limitations, and be done with it. The other solution is to distribute two versions of your solution: one for ‘x86′ and one for ‘x64′. There is a whole boatload of options that you need to tweak on the C++/CLI assembly to get it to compile in 64-bit–check MSDN, and double-check my typedefs, as I wouldn’t be surprised if I borked something up. Unfortunately, we’re getting out of my domain of expertise here. Good luck!

  37. I am curious if you had a specific reason why you created a separate class implementing IMessageFilter to suppress next WM_KEYDOWN rather than just use a boolean in the original class and watch for WM_KEYDOWN in the existing WndProc() method? Was there a timing/coordination problem, or is WndProc() not receiving WM_KEYDOWN messages? Also, why not suppressing the WM_KEYUP messages? Shouldn’t both WM_KEYDOWN and WM_KEYUP be suppressed as a pair?

  38. Nicholas, Thanks for the info. I am trying to get this code to work on my system and I have traced the problem to the following code in the ProcessRawInputMessage(IntPtr rawInputHeader) method.

        if (localBuffer.Length == 1 &amp;&amp; localBuffer[0] == 0x4)
        {
            this.FireBarcodeScanned(deviceInfo);
        }
        else
        {
            this.keystrokeBuffer.Append(localBuffer);
        }
    

    When I scan barcodes “localBuffer[0] == 0×4″ never is true therefore this.FireBarcodeScanned(deviceInfo); is never called. Any ideas on how I may fix this?

  39. Excellent article!! This is exactly what I am looking for, BUT… Has anyone successfully ported this to vb.net? Would anyone be willing to help me on this?

  40. Tom,

    You asked how you can fix the localbuffer not equalling 0×4. The answer is simple.

    If you read somewhere in middle , Nicholas writes that all their scanners are configured to send 0×4 ( EOT character ) so that’s why it works for him.

    You can change it to the \r character or carriage return which is standard for scanners. I think the value is 0xD , you can check . That should do it. Maybe it should have been a value in the app.config file instead of hardcoded.

  41. Hi,

    I have gotten this program to work and it’s a real amazing piece of code.

    However :( – unfortunately it does not solve my problem.

    Because I’d like the user of the computer to not know at all that the barcode scanner read anything. I need the keyboard to not send any keys to the focused application, and only to the program you’ve written.

    Alas, even when I change the flag to RIDEV_EXINPUTSINK, It doesn’t stop the keys from being shown on a word program or whatever program user is using.

    This means I cannot use one computer to multitask, allowing user to work normally, while having some guy using a scan gun to scan things.

    Do you have any other suggestions???

    I’d appreciate it.

    Thanks.

  42. I’m actually hitting the same problem as Ryan Helms and paeppi with regards to running on a 64bit but setting the project to run in x86. all compiles correctly but doesn’t seem to fire the barcodescanned event.

    I followed the code through and it seems like not all the barcode characters are being picked up by the following method: protected override void WndProc(ref Message m)

    for example: If I scan a barcode (code 39) that says ‘ABC123′. the first character picked up is empty (”) the next character picked up by the WndProc is the first letter (A) of the barcode. it doesn’t pick up anymore characters and thus doesn’t get to the end of the barcode meaning that

    if (localBuffer.Length == 1 && localBuffer[0] == 0×4) { … } is never true

    i understand that the end of your barcode has the EOT character. but this makes no difference in this case because the full barcode isn’t read.

    strange

  43. Great Article!, but when trying to use your revised version, I’m getting a strange behavior with MessageBox, it always ignore the first MessageBox.Show in the BarcodeScanned handler

    Any idea?

    public MainForm() { this.InitializeComponent();

            BarcodeScannerListener listener = new BarcodeScannerListener();
            listener.Attach(this);
            listener.BarcodeScanned += this.OnBarcodeScanned;
        }

    private void OnBarcodeScanned(object sender, EventArgs e)
    {
        BarcodeScannedEventArgs be = e as BarcodeScannedEventArgs;
    
        if (be != null)
        {
            this.Text = be.Barcode;
    
            MessageBox.Show("message 1"); //will not show up!
            MessageBox.Show("message 2"); //will show up
        }
    }
    

  44. I have successfully accomplished what you folks are looking for here. I have an application that receives all barcode character data from a Honeywell/Metrologic barcode scanner. No other application on the system receives the data from the scanner, and the keyboard continues to function normally.

    My application uses a combination of raw input and the dreaded low-level keyboard hook system. Contrary to what is written here, I found that the wm_input message is received before the keyboard hook function is called. My code to process the wm_input message basically sets a boolean variable to specify whether or not the received character is from the scanner. The keyboard hook function, called immediately after the wm_input is processed, swallows the scanner’s pseudo-keyboard data, preventing the data from being received by other applications.

    The keyboard hook function has to be placed in an dll since you want to intercept all system keyboard messages. Also, a memory mapped file has to be used for the wm_input processing code to communicate with the dll.

    • Is Posible you to send me sample code . THanks

      Cos im having error “The type or namespace name ‘Interop’ does not exist in the namespace ‘BarcodeSample.UI.WinForms’ . And i dont know how to fixed.

    • Hello my friend sorry for my bad english I am looking a code like yours if you can help me please send me your peace of code to this email ljrc19@hotmail.com, I am hairless trying to do that no other applications get the barcode entries but my application have to get it!, so I will thank you your help!

    • Can you please publish your code so I can download it. I’ve spent many days on this so far and seem to be going around in circles most of the time!

  45. Thank you so much for taking the extra time to both write this blog post and to update it with an even better solution.

    This helped me out when trying to separate input from a rfid-reader that also works under cover as a keyboard.

    There is however a very big gotcha that I discovered when incorporating the ideas in here into my project: WPF does not support message filtering in the same way! Thankfully the solution is really simple: Instead of “Application.AddMessageFilter” use ComponentDispatcher.ThreadFilterMessage.

    You add a new ThreadMessageEventHandler to this event, and in this method you can check if you should filter this message. if you should, then simply set handled to true in the event handler and it will be surpressed in the application like before.

  46. Please HELP ME. i got this error even from your compiled versions in the “bin\Debug” folder. ———> System.BadImageFormatException. im using windows 7 x64 and vs 2010

  47. I downloaded the revised version n open the app in vs2010 ,im getting this error “The type or namespace name ‘Interop’ does not exist in the namespace ‘BarcodeSample.UI.WinForms’ “

    If any knows this error please guide me to fix this one Thanks

  48. Hi,

    I’ve successfully gotten the updated code to compile and work on VS2010 on Win7 x64 – there’s an error in a conditional making it never show any key input data at all.

    Basically -

    if (raw.keyboard.Message == WM_KEYDOWN || raw.keyboard.Message == WM_SYSKEYDOWN)

    needs to become

    if (raw.keyboard.Message != WM_KEYDOWN && raw.keyboard.Message != WM_SYSKEYDOWN)

    or the like.

    Also, you’ll need to comment out throwing an ApplicationException if the device handle was not in the hashtable. Many barcode or – in my case – mag swipe readers are non-standard keyboards ;)

    In any case, thanks for starting me off in the right direction – Greg Bergmann’s approach seems interesting.

    • I downloaded the revised version n open the app in vs2010 ,im getting this error “The type or namespace name ‘Interop’ does not exist in the namespace ‘BarcodeSample.UI.WinForms’ “ Can you send me the source code (project) you used in VS 2010 Win7x64 ? Thanks!

  49. This article is what i am looking for. but i dont became a pop up page with my barcode.I change the value 0×4 with 0xD. what i have forget to do. please help me

  50. Awesome article, thanks. This seems to be exactly what I was looking for. Anyway, I need some guidance on how to compile this project on my VS 2011 + W7x64.

    Could someone post an updated version of the projects/solution files, with a “clean” compilation? I got a bunch of errors, here. Couldn’t even test it.

    I’m kinda new to C# and VS-C++, so sorry if I missed something.

  51. Hi,

    I’ve download the updated file and when I try to run it I get the exception: Could not load file or assembly ‘BarcodeSample.UI.WinForms.Interop.

    Why is that ?

  52. Good article Nicholas.. Sam, for some reason the MessageBox don’t appear in normal mode, because (i think) of the carriage return at the end of the barcode string. If you debug the program or if you add a textbox field and write in the text field “be.Barcode” .then you can see that the program works well ;)

  53. I also got this error message: I downloaded the revised version and opened the app in vs2010 express C#, i’m getting this error “The type or namespace name ‘Interop’ does not exist in the namespace ‘BarcodeSample.UI.WinForms’ “

    If anybody knows the solution to this error please guide us to fix it. Thanks

  54. Also: The referenced project ‘..\BarcodeSample.UI.WinForms.Interop\BarcodeSample.UI.WinForms.Interop.vcxproj’ does not exist.

    and that’s true. But there is: BarcodeSample.UI.WinForms.Interop.vcproj So without the x in vcxproj

  55. Hi,

    My scanner ends the code with an \r 0×13 and an ETB 0×17 i checked by reading keyUp events in a TextBox. But in the ProcessRawInputMessage method all I can see are one \r and one \n chars at the end of the code.

    Does anyone know why this happens?

    I’d appreciate any help.

    Thanks.

  56. Hi. Cheers for the great article!

    However, as far as I can see you manually included the device name in the App.config file ? So you’re actually using 2 facts to identify uniquely the scanner gun: the name of the device provided by the manifacturer and the user-defined suffix on the scanner.

  57. Hi, your code has provided half solution to my problem. The other half was provided by this guy http://nate.dynalias.net/dev/keyboardredirector.rails that has found out an interesting behaviour of keyboard hooks: WH_KEYBOARD_LL happens before the WM_INPUT message WH_KEYBOARD happens after the WM_INPUT message This should let the program blocks keystrokes from a selected keyboard

    Thanks a lot for sharing your knowledge

    • How did you remove the keystroke using SetWindowsHookEx and WH_KEYBOARD?

      I’ve tried with “return 1″ in the callback and did not work.

  58. Great Article! I converted the project to VS2010 .Net 4.0 and compiled without errors. But, the event OnBarcodeScanned never get fire. I am testing with a symbol ls2208 USB scanner on Window Vista 32-bit OS.

    The scanner has been configured as USB HID. From the device manage, I obtain the Guid and HID and change the code as:

    Guid GUID_DEVINTERFACE_HID = new Guid(“{6960CCCC-B19D-6B41-80FA-552DA52B69B4}”);

    Any suggestions what the problem could be?

    Thanks Tom

  59. I get this error :”Could not load file or assembly ‘BarcodeSample.UI.WinForms.Interop, Version=1.0.4745.28052, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. An attempt was made to load a program with an incorrect format.” in Main Form on this line: listener = new BarcodeScannerListener();

    • In Configuration Manager, change all of the projects to x86 or x64. I left the main project at AnyCPU, which can cause mismatches with the Interop assembly (set to x86) when compiled on x64 machines.

  60. Wonderfull piece of work. Works like a charm for all scanners tested so far.

    Not sure if I should bother YOU with this, but I have a question : in default mode, the scanner sends a WM_KEYDOWN and a WM_KEYUP for every character scanned. No problems there. Today, I had a scanner refusing to be recognized, until I found out it was configured as USB-KBD-ALT-MODE. Any idea where I can find more information about this “alt-mode”? The scanner appears to send 8 messages per character scanned, most of type WM_SYSKEYDOWN.

    • Open Configuration Manager and change all of the architectures to either x86 or x64. I developed it on an old 32-bit laptop back in the day and didn’t notice it was still set to AnyCPU. If you have one assembly as AnyCPU and another as x86 on an x64 machine, you’ll get problems.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>