3年前写了一篇《USB口的红外条形码扫描器的另类使用》,不过相关代码是VB编写,在这几年之间,有许多网友提出需要C#版的,起初还以为由VB修改C#应该很容易,最近研究了一下,发现C#和VB调用API的机制还是有所不同的,在迁移的过程中还是会遇到不少问题,所以我专门抽时间做了一个基于C#的程序。

【目前的条形码扫描器有点类似外接键盘(其实从消息传送上它就相当于一个键盘),把输入焦点定位到可输入的控件上,一扫描相应的条形码信息就输入到文本框中去了,但是如果没有输入焦点,或另一个不相干的程序获得输入焦点,那就有点乱套了。我想实现的是,不管什么情况,只要扫描器一工作,我的程序就能自动激活,并能获得当前输入的条形码信息。 实现思路:我用的是litele牌的USB口的红外条形码扫描器,仔细分析了一下,扫描成功后,以键盘按键消息的形式把条形码输入信息通知给系统。这样通过键盘钩子就可以方便的获得该信息了。但是,怎样区分信息是键盘还是条形码输入的哪?很简单,条形码扫描器在很短的时间内输入了至少3个字符以上信息,并且以“回车”作为结束字符,在这种思想指引下,很完美的实现了预定功能。】

VB相关的代码请见:http://blog.csdn.net/yefanqiu/archive/2006/08/30/1144881.aspx


窗体相关代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms; namespace ReadBadCode
{
public partial class frmTest : Form
{
BarCodeHook BarCode = new BarCodeHook();
public frmTest()
{
InitializeComponent();
BarCode.BarCodeEvent += new BarCodeHook.BarCodeDelegate(BarCode_BarCodeEvent);
} private delegate void ShowInfoDelegate(BarCodeHook.BarCodes barCode);
private void ShowInfo(BarCodeHook.BarCodes barCode)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new ShowInfoDelegate(ShowInfo), new object[] { barCode });
}
else
{
textBox1.Text = barCode.KeyName;
textBox2.Text = barCode.VirtKey.ToString();
textBox3.Text = barCode.ScanCode.ToString();
textBox4.Text = barCode.AscII.ToString();
textBox5.Text = barCode.Chr.ToString();
textBox6.Text = barCode.IsValid ? barCode.BarCode : "";
}
} void BarCode_BarCodeEvent(BarCodeHook.BarCodes barCode)
{
ShowInfo(barCode);
} private void frmTest_Load(object sender, EventArgs e)
{
BarCode.Start();
} private void frmTest_FormClosed(object sender, FormClosedEventArgs e)
{
BarCode.Stop();
} private void textBox6_TextChanged(object sender, EventArgs e)
{
if (textBox6.Text.Length > 0)
{
MessageBox.Show(textBox6.Text);
}
}
}
}

BarCodeHook 类:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection; namespace ReadBadCode
{
public class BarCodeHook
{
public delegate void BarCodeDelegate(BarCodes barCode);
public event BarCodeDelegate BarCodeEvent; public struct BarCodes
{
public int VirtKey; //虚拟码
public int ScanCode; //扫描码
public string KeyName; //键名
public uint AscII; //AscII
public char Chr; //字符 public string BarCode; //条码信息
public bool IsValid; //条码是否有效
public DateTime Time; //扫描时间
} private struct EventMsg
{
public int message;
public int paramL;
public int paramH;
public int Time;
public int hwnd;
} [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(int idHook); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam); [DllImport("user32", EntryPoint = "GetKeyNameText")]
private static extern int GetKeyNameText(int lParam, StringBuilder lpBuffer, int nSize); [DllImport("user32", EntryPoint = "GetKeyboardState")]
private static extern int GetKeyboardState(byte[] pbKeyState); [DllImport("user32", EntryPoint = "ToAscii")]
private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeyState, ref uint lpChar, int uFlags); delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
BarCodes barCode = new BarCodes();
int hKeyboardHook = 0;
string strBarCode = ""; private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
if (nCode == 0)
{
EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg)); if (wParam == 0x100) //WM_KEYDOWN = 0x100
{
barCode.VirtKey = msg.message & 0xff; //虚拟码
barCode.ScanCode = msg.paramL & 0xff; //扫描码 StringBuilder strKeyName = new StringBuilder(255);
if (GetKeyNameText(barCode.ScanCode * 65536, strKeyName, 255) > 0)
{
barCode.KeyName = strKeyName.ToString().Trim(new char[] { ' ', '/0' });
}
else
{
barCode.KeyName = "";
} byte[] kbArray = new byte[256];
uint uKey = 0;
GetKeyboardState(kbArray);
if (ToAscii(barCode.VirtKey, barCode.ScanCode, kbArray, ref uKey, 0))
{
barCode.AscII = uKey;
barCode.Chr = Convert.ToChar(uKey);
} if (DateTime.Now.Subtract(barCode.Time).TotalMilliseconds > 50)
{
strBarCode = barCode.Chr.ToString();
}
else
{
if ((msg.message & 0xff) == 13 && strBarCode.Length > 3) //回车
{
barCode.BarCode = strBarCode;
barCode.IsValid = true;
}
strBarCode += barCode.Chr.ToString();
} barCode.Time = DateTime.Now;
if (BarCodeEvent != null) BarCodeEvent(barCode); //触发事件
barCode.IsValid = false;
}
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
} // 安装钩子
public bool Start()
{
if (hKeyboardHook == 0)
{
//WH_KEYBOARD_LL = 13
hKeyboardHook = SetWindowsHookEx(13, new HookProc(KeyboardHookProc), Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
}
return (hKeyboardHook != 0);
} // 卸载钩子
public bool Stop()
{
if (hKeyboardHook != 0)
{
return UnhookWindowsHookEx(hKeyboardHook);
}
return true;
}
}
}

【注意】和VB程序不同,要想测试实际的效果,必须执行编译后的Exe文件,在开发环境直接运行会没有效果的。

C# Winform中无焦点状态下获取键盘输入或者USB扫描枪数据

类文件:

  1 using System;

  2 using System.Collections.Generic;

  3 using System.Text;

  4 using System.Runtime.InteropServices;

  5 using System.Reflection;

  6 

  7 namespace Common

  8 {

  9     public class BardCodeHooK

 10     {

 11         public delegate void BardCodeDeletegate(BarCodes barCode);

 12         public event BardCodeDeletegate BarCodeEvent;

 13 

 14         public struct BarCodes

 15         {

 16             public int VirtKey;//虚拟吗

 17             public int ScanCode;//扫描码

 18             public string KeyName;//键名

 19             public uint Ascll;//Ascll

 20             public char Chr;//字符

 21 

 22             public string BarCode;//条码信息

 23             public bool IsValid;//条码是否有效

 24             public DateTime Time;//扫描时间

 25         }

 26 

 27         private struct EventMsg

 28         {

 29             public int message;

 30             public int paramL;

 31             public int paramH;

 32             public int Time;

 33             public int hwnd;

 34         }

 35 

 36         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

 37         private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

 38 

 39         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

 40         private static extern bool UnhookWindowsHookEx(int idHook);

 41 

 42         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

 43         private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

 44 

 45         [DllImport("user32", EntryPoint = "GetKeyNameText")]

 46         private static extern int GetKeyNameText(int IParam, StringBuilder lpBuffer, int nSize);

 47 

 48         [DllImport("user32", EntryPoint = "GetKeyboardState")]

 49         private static extern int GetKeyboardState(byte[] pbKeyState);

 50 

 51         [DllImport("user32", EntryPoint = "ToAscii")]

 52         private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeySate, ref uint lpChar, int uFlags);

 53 

 54         delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

 55         BarCodes barCode = new BarCodes();

 56         int hKeyboardHook = 0;

 57         string strBarCode = "";

 58 

 59         private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)

 60         {

 61             if (nCode == 0)

 62             {

 63                 EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));

 64                 if (wParam == 0x100)//WM_KEYDOWN=0x100

 65                 {

 66                     barCode.VirtKey = msg.message & 0xff;//虚拟吗

 67                     barCode.ScanCode = msg.paramL & 0xff;//扫描码

 68                     StringBuilder strKeyName = new StringBuilder(225);

 69                     if (GetKeyNameText(barCode.ScanCode * 65536, strKeyName, 255) > 0)

 70                     {

 71                         barCode.KeyName = strKeyName.ToString().Trim(new char[] { ' ', '\0' });

 72                     }

 73                     else

 74                     {

 75                         barCode.KeyName = "";

 76                     }

 77                     byte[] kbArray = new byte[256];

 78                     uint uKey = 0;

 79                     GetKeyboardState(kbArray);

 80 

 81 

 82                     if (ToAscii(barCode.VirtKey, barCode.ScanCode, kbArray, ref uKey, 0))

 83                     {

 84                         barCode.Ascll = uKey;

 85                         barCode.Chr = Convert.ToChar(uKey);

 86                     }

 87 

 88                     TimeSpan ts = DateTime.Now.Subtract(barCode.Time);

 89 

 90                     if (ts.TotalMilliseconds > 50)

 91                     {

 92                         strBarCode = barCode.Chr.ToString();

 93                     }

 94                     else

 95                     {

 96                         if ((msg.message & 0xff) == 13 && strBarCode.Length > 3)

 97                         {

 98                             barCode.BarCode = strBarCode;

 99                             barCode.IsValid = true;

100                         }

101                         strBarCode += barCode.Chr.ToString();

102                     }

103                     barCode.Time = DateTime.Now;

104                     if (BarCodeEvent != null) BarCodeEvent(barCode);//触发事件

105                     barCode.IsValid = false;

106                 }

107             }

108             return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);

109         }

110 

111         //安装钩子

112         public bool Start()

113         {

114             if (hKeyboardHook == 0)

115             {

116                 //WH_KEYBOARD_LL=13

117                 hKeyboardHook = SetWindowsHookEx(13, new HookProc(KeyboardHookProc), Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);

118             }

119             return (hKeyboardHook != 0);

120         }

121 

122         //卸载钩子

123         public bool Stop()

124         {

125             if (hKeyboardHook != 0)

126             {

127                 return UnhookWindowsHookEx(hKeyboardHook);

128             }

129             return true;

130         }

131     }

132 }

页面中用法:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

namespace Common

{

    public partial class FrmMain : Form

    {

        BardCodeHooK BarCode = new BardCodeHooK();

        public FrmMain()

        {

            InitializeComponent();

            BarCode.BarCodeEvent += new BardCodeHooK.BardCodeDeletegate(BarCode_BarCodeEvent);

        }

        private delegate void ShowInfoDelegate(BardCodeHooK.BarCodes barCode);

        private void ShowInfo(BardCodeHooK.BarCodes barCode)

        {

            if (this.InvokeRequired)

            {

                this.BeginInvoke(new ShowInfoDelegate(ShowInfo), new object[] { barCode });

            }

            else

            {

                textBox1.Text = barCode.KeyName;

                textBox2.Text = barCode.VirtKey.ToString();

                textBox3.Text = barCode.ScanCode.ToString();

                textBox4.Text = barCode.Ascll.ToString();

                textBox5.Text = barCode.Chr.ToString();

                textBox6.Text = barCode.IsValid? barCode.BarCode : "";//是否为扫描枪输入,如果为true则是 否则为键盘输入

                textBox7.Text += barCode.KeyName;

                //MessageBox.Show(barCode.IsValid.ToString());

            }

        }

        //C#中判断扫描枪输入与键盘输入

        //Private DateTime _dt = DateTime.Now;  //定义一个成员函数用于保存每次的时间点

        //private void textBox1_KeyPress(object sender, KeyPressEventArgs e)

        //{

        //    DateTime tempDt = DateTime.Now;          //保存按键按下时刻的时间点

        //    TimeSpan ts = tempDt .Subtract(_dt);     //获取时间间隔

        //    if (ts.Milliseconds > 50)                           //判断时间间隔,如果时间间隔大于50毫秒,则将TextBox清空

        //        textBox1.Text = "";

        //    dt = tempDt ;

        //}

 

        void BarCode_BarCodeEvent(BardCodeHooK.BarCodes barCode)

        {

            ShowInfo(barCode);

        }

        private void FrmMain_Load(object sender, EventArgs e)

        {

            BarCode.Start();

        }

        private void FrmMain_FormClosed(object sender, FormClosedEventArgs e)

        {

            BarCode.Stop();

        }

        private void textBox6_TextChanged(object sender, EventArgs e)

        {

            if (textBox6.Text.Length > 0)

            {

                MessageBox.Show("条码长度:" + textBox6.Text.Length + "\n条码内容:" + textBox6.Text, "系统提示");

            }

        }

    }

}

红外条码扫描器的另类使用C#版的更多相关文章

  1. 超强工具集——GitHub 热点速览 Vol.47

    作者:HelloGitHub-小鱼干 本周 GitHub 趋势榜精彩至极,先是 JetBrains 开源的图像渲染引擎 Skia 有了 Java 封装,一开源便获得 500+ star,再是支持开发者 ...

  2. Revealjs网页版PPT让你复制粘贴另类装逼,简洁优雅又低调,不懂编程也看过来

    Revealjs网页版PPT让你复制粘贴另类装逼,简洁优雅又低调,不懂编程也看过来 要了解一个新知识我们可以从三个方面入手:是什么,有什么用,怎么用.下面我们就从这三个方面进行讲解Reveal.js噢 ...

  3. ETO的公开赛T1《矿脉开采》题解(另类版)

    这道题别看是签到题,写起来一点不简单 出题人的正解是双向搜索 我们把物品分成两半 每一半分别跑搜索 答案存下来,用个双指针合并即可 然后我构造了两组数据卡掉了他,不得不缩小数据范围 但我这里为什么要致 ...

  4. 智能手机+DIY红外=万能遥控器

    目前好像只有:三星S4.,努比亚大牛,华为荣耀3等几款新机才有红外遥控功能,那我们使用的手机没有这个功能怎么办?不要急我有办法呵呵,本次DIY材料好找又简单,大家都可以亲自试一试! DIY材料:红外二 ...

  5. 【Win 10 应用开发】RTM版的UAP项目解剖

    Windows 10 发布后,其实SDK也偷偷地在VS的自定义安装列表中出现了,今天开发人员中心也更新了下载.正式版的SDK在API结构上和以前预览的时候是一样的,只是版本变成10240罢了,所以大家 ...

  6. Android开发权威指南(第2版)新书发布

    <Android 开发权威指南(第二版)>是畅销书<Android开发权威指南>的升级版,内容更新超过80%,是一本全面介绍Android应用开发的专著,拥有45 章精彩内容供 ...

  7. TVB-Gone 红外编码方法

    每次都重新推算一遍,年纪大了还是记录一下吧(硬件版的TV-B-Gone的压缩编码跳过此段往下看) N900上有个TVB-Gone的程序,但是程序的红外编码往往都是对应的国外的电视,好多国产电视都不支持 ...

  8. 全球最受欢迎的十大Linux发行版(图)

    帮助新的Linux用户在越来越多的Linux发行版中选择最合适的操作系统,是创建这个网页的原因.它列出了迄今为止最流行的10个Linux发行版(另外增加的是FreeBSD,到目前为止最为流行的BSD系 ...

  9. Java面试宝典2013版(超长版)

    一. Java基础部分......................................................................................... ...

随机推荐

  1. CSS字体大小之em,px,百分比

    首先要记住网页中常规字体的大小为16px. px是用来设置字体的绝对大小.通常为用于物理值的设置.我们在互联网上看到的常规字体大小为16px.而em是指相对于父元素的大小.1em是父元素的1倍,2em ...

  2. shell脚本--权限分配

    因为shell脚本内部是很多命令的集合,这些命令也许会涉及到操作某一个文件,而且shell脚本的运行,也是需要当前用户对脚本具有运行的权限,否则,会因为权限不够而失败. 首先最重要的一点:修改权限,只 ...

  3. Git 换行符检查 CRLF 与 LF

    遇到的问题 在 git 提交或是签出时,提示如下问题: [git] warning: LF will be replaced by CRLF | fatal: CRLF would be replac ...

  4. XE2 运行时 item not found的解决办法

    .net类库的原因. 将C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG下面的 machine.config.default 改名为machin ...

  5. Ubuntu 16.04 root环境变量不生效问题解决方案

    在Ubuntu 16.04中配置JDK环境变量,但是在切换到root时不生效 . 在/etc/profile中添加如下: export JAVA_HOME=/opt/java/jdk1..0_151 ...

  6. 2.18比赛(T2,T3留坑)

    2.18比赛(T2,T3留坑) pdf版题面 pdf版题解 超越一切(ak) [题目描述] 夏洛可得到一个(h+1)×(w+1)的巧克力,这意味着她横着最多可 以切 h 刀,竖着最多可以切 w 刀 她 ...

  7. 【题解】ID分配

    题目描述 您正在处理要为每个客户端分配唯一ID的特定系统的后端.但是,系统是分布式的,并且有许多组件,每个组件都必须能够为客户端分配ID.换句话说,您希望每个组件都使用尽可能少的组件之间的通信来分配I ...

  8. Catenyms POJ - 2337(单词+字典序输出路径)

    题意: 就是给出几个单词 看能否组成欧拉回路或路径  当然还是让输出组成的最小字典序的路 解析: 还是把首尾字母看成点   把单词看成边 记录边就好了 这题让我对fleury输出最小字典序又加深了一些 ...

  9. MT【52】空间法向量理解直线条数

    [从最简单的做起.]--波利亚 评:线面角转化成线与线的角,这道题还有类似的这类题是学生的难点.

  10. Leetcode 237.删除链表中的节点 By Python

    请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点. 现有一个链表 -- head = [4,5,1,9],它可以表示为: 4 -> 5 -> 1 - ...