目前的条形码扫描器有点类似外接键盘(其实从消息传送上它就相当于一个键盘),把输入焦点定位到可输入的控件上,一扫描相应的条形码信息就输入到文本框中去了,但是如果没有输入焦点,或另一个不相干的程序获得输入焦点,那就有点乱套了。我想实现的是,不管什么情况,只要扫描器一工作,我的程序就能自动激活,并能获得当前输入的条形码信息。
实现思路:我用的USB口的条形码扫描器,仔细分析了一下,扫描成功后,以键盘按键消息的形式把条形码输入信息通知给系统。这样通过键盘钩子就可以方便的获得该信息了。但是,怎样区分信息是键盘还是条形码输入的哪?
很简单,条形码扫描器在很短的时间内输入了至少3个字符以上信息,并且以“回车”作为结束字符,在这种思想指引下,很完美的实现了预定功能。
以下程序要在Win2000/Win XP 下才能运行成功。
form1 中的代码:
'*************************************************************************
Option Explicit
Private Sub Form_Load()
SetHook
End Sub
Private Sub Form_Unload(Cancel As Integer)
UnHook
End Sub
Private Sub tmrScan_Timer()
Dim strBarCode As String
strBarCode = GetBarCode
If Len(strBarCode) > 0 Then
MsgBox "条形码:" & strBarCode
End If
End Sub
模块中的代码:
'*************************************************************************
'**模 块 名:basBarCode
'**描 述:获取条形码数据
'**版 本:V1.0.0
'*************************************************************************
Option Explicit
Private Type KeyboardBytes
kbByte(0 To 255) As Byte
End Type
Dim kbArray As KeyboardBytes
Private Declare Function GetKeyboardState Lib "user32" (pbKeyState As KeyboardBytes) As Long
Private Declare Function ToAscii Lib "user32" (ByVal uVirtKey As Long, ByVal uScanCode As Long, lpbKeyState As KeyboardBytes, lpwTransKey As Long, ByVal fuState As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, ByVal lpvSource As Long, ByVal cbCopy As Long)
Private Declare Function GetKeyNameText Lib "user32" Alias "GetKeyNameTextA" (ByVal lParam As Long, ByVal lpBuffer As String, ByVal nSize As Long) As Long
Private Type EVENTMSG
message As Long
paramL As Long
paramH As Long
Time As Long
hwnd As Long
End Type
Private Type BARCODES
VirtKey As Long '虚拟码
ScanCode As Long '扫描码
KeyName As String '键的名称
AscII As Long 'AscII
Chr As String '字符
BarCode As String '扫描码信息
Time As Date '扫描时间
bGetFlag As Boolean '是否已获取扫描码
End Type
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function GetCurrentTime Lib "kernel32" Alias "GetTickCount" () As Long
Private Const WH_KEYBOARD_LL = 13
Private m_lHook As Long
Public g_BarCode As BARCODES
'*************************************************************************
'**函 数 名:SetHook / UnHook
'**输 入:无
'**输 出:无
'**功能描述:装卸钩子
'**全局变量:
'**调用模块:
'**版 本:V1.0.0
'*************************************************************************
Public Sub SetHook()
m_lHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf CallHookProc, App.hInstance, 0)
End Sub
Public Sub UnHook()
If m_lHook <> 0 Then
UnhookWindowsHookEx m_lHook
End If
End Sub
'*************************************************************************
'**函 数 名:GetBarCode
'**输 入:无
'**输 出:(String) -
'**功能描述:获取扫描码
'**全局变量:
'**调用模块:
'**版 本:V1.0.0
'*************************************************************************
Public Function GetBarCode() As String
If g_BarCode.bGetFlag = True Then
g_BarCode.bGetFlag = False
GetBarCode = g_BarCode.BarCode
Else
GetBarCode = ""
End If
End Function
'*************************************************************************
'**函 数 名:CallHookProc
'**输 入:ByVal code(Long) -
'** :ByVal wParam(Long) -
'** :ByVal lParam(Long) -
'**输 出:(Long) -
'**功能描述:
'**全局变量:
'**调用模块:
'**版 本:V1.0.0
'*************************************************************************
Private Function CallHookProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim msg As EVENTMSG
Dim strKeyName As String
Dim lngKey As Long
Static lngTime As Long
Static strBarCode As String
If code = 0 Then
CopyMemory msg, lParam, LenB(msg)
If wParam = &H100 Then 'WM_KEYDOWN
g_BarCode.VirtKey = msg.message And &HFF '虚拟码
g_BarCode.ScanCode = msg.paramL And &HFF '扫描码
strKeyName = Space(255)
If GetKeyNameText(g_BarCode.ScanCode * 65536, strKeyName, 255) > 0 Then '键名
g_BarCode.KeyName = Trim(strKeyName)
Else
g_BarCode.KeyName = ""
End If
'---------------------------------------
Call GetKeyboardState(kbArray)
If ToAscii(g_BarCode.VirtKey, g_BarCode.ScanCode, kbArray, lngKey, 0) > 0 Then
g_BarCode.AscII = lngKey
g_BarCode.Chr = Chr(lngKey)
End If
'--------------------
If Abs(GetCurrentTime - lngTime) > 50 Then
strBarCode = g_BarCode.Chr
Else
If (msg.message And &HFF) = 13 And Len(strBarCode) > 3 Then '回车
g_BarCode.BarCode = strBarCode
g_BarCode.Time = Now
g_BarCode.bGetFlag = True
End If
strBarCode = strBarCode & g_BarCode.Chr
End If
lngTime = GetCurrentTime
'---------------------------------------
'测试代码
’Call ShowKeyInfo
'---------------------------------------
End If
End If
CallHookProc = CallNextHookEx(m_lHook, code, wParam, lParam)
End Function
'显示调试信息
Public Sub ShowKeyInfo()
frmDemo.txtKey(0) = g_BarCode.KeyName
frmDemo.txtKey(1) = g_BarCode.VirtKey
frmDemo.txtKey(2) = g_BarCode.ScanCode
frmDemo.txtKey(3) = g_BarCode.AscII
frmDemo.txtKey(4) = g_BarCode.Chr
frmDemo.txtBarCode = g_BarCode.BarCode