C#获取扫码枪扫描数据并处理
生活随笔
收集整理的這篇文章主要介紹了
C#获取扫码枪扫描数据并处理
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
開發原因:工廠產品需要頻繁掃描產品SN進行產品踢轉處理不良以及工單結多產品
直接上代碼:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text;namespace WindowsFormsApplication6 {internal class ScanerHook{public delegate void ScanerDelegate(ScanerCodes codes);public event ScanerDelegate ScanerEvent;//private const int WM_KEYDOWN = 0x100;//KEYDOWN //private const int WM_KEYUP = 0x101;//KEYUP //private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN //private const int WM_SYSKEYUP = 0x105;//SYSKEYUP//private static int HookProc(int nCode, Int32 wParam, IntPtr lParam);private int hKeyboardHook = 0;//聲明鍵盤鉤子處理的初始值private ScanerCodes codes = new ScanerCodes();//13為鍵盤鉤子//定義成靜態,這樣不會拋出回收異常private static HookProc hookproc;delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);[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 IParam, StringBuilder lpBuffer, int nSize);[DllImport("user32", EntryPoint = "GetKeyboardState")] //獲取按鍵的狀態private static extern int GetKeyboardState(byte[] pbKeyState);[DllImport("user32", EntryPoint = "ToAscii")] //ToAscii職能的轉換指定的虛擬鍵碼和鍵盤狀態的相應字符或字符private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeySate, ref uint lpChar, int uFlags);//int VirtualKey //[in] 指定虛擬關鍵代碼進行翻譯。 //int uScanCode, // [in] 指定的硬件掃描碼的關鍵須翻譯成英文。高階位的這個值設定的關鍵,如果是(不壓) //byte[] lpbKeyState, // [in] 指針,以256字節數組,包含當前鍵盤的狀態。每個元素(字節)的數組包含狀態的一個關鍵。如果高階位的字節是一套,關鍵是下跌(按下)。在低比特,如/果設置表明,關鍵是對切換。在此功能,只有肘位的CAPS LOCK鍵是相關的。在切換狀態的NUM個鎖和滾動鎖定鍵被忽略?! ?/byte[] lpwTransKey, // [out] 指針的緩沖區收到翻譯字符或字符?! ?/uint fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.[DllImport("kernel32.dll")] //使用WINDOWS API函數代替獲取當前實例的函數,防止鉤子失效public static extern IntPtr GetModuleHandle(string name);public ScanerHook(){}public bool Start(){if (hKeyboardHook == 0){hookproc = new HookProc(KeyboardHookProc);//GetModuleHandle 函數 替代 Marshal.GetHINSTANCE //防止在 framework4.0中 注冊鉤子不成功 IntPtr modulePtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);//WH_KEYBOARD_LL=13 //全局鉤子 WH_KEYBOARD_LL // hKeyboardHook = SetWindowsHookEx(13, hookproc, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0); hKeyboardHook = SetWindowsHookEx(13, hookproc, modulePtr, 0);}return (hKeyboardHook != 0);}public bool Stop(){if (hKeyboardHook != 0){bool retKeyboard = UnhookWindowsHookEx(hKeyboardHook);hKeyboardHook = 0;return retKeyboard;}return true;}private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam){EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));codes.Add(msg);if (ScanerEvent != null && msg.message == 13 && msg.paramH > 0 && !string.IsNullOrEmpty(codes.Result)){ScanerEvent(codes);}return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);}public class ScanerCodes{private int ts = 300; // 指定輸入間隔為300毫秒以內時為連續輸入 private List<List<EventMsg>> _keys = new List<List<EventMsg>>();private List<int> _keydown = new List<int>(); // 保存組合鍵狀態 private List<string> _result = new List<string>(); // 返回結果集 private DateTime _last = DateTime.Now;private byte[] _state = new byte[256];private string _key = string.Empty;private string _cur = string.Empty;public EventMsg Event{get{if (_keys.Count == 0){return new EventMsg();}else{return _keys[_keys.Count - 1][_keys[_keys.Count - 1].Count - 1];}}}public List<int> KeyDowns{get{return _keydown;}}public DateTime LastInput{get{return _last;}}public byte[] KeyboardState{get{return _state;}}public int KeyDownCount{get{return _keydown.Count;}}public string Result{get{if (_result.Count > 0){return _result[_result.Count - 1].Trim();}else{return null;}}}public string CurrentKey{get{return _key;}}public string CurrentChar{get{return _cur;}}public bool isShift{get{return _keydown.Contains(160);}}public void Add(EventMsg msg){#region 記錄按鍵信息 // 首次按下按鍵 if (_keys.Count == 0){_keys.Add(new List<EventMsg>());_keys[0].Add(msg);_result.Add(string.Empty);}// 未釋放其他按鍵時按下按鍵 else if (_keydown.Count > 0){_keys[_keys.Count - 1].Add(msg);}// 單位時間內按下按鍵 else if (((TimeSpan)(DateTime.Now - _last)).TotalMilliseconds < ts){_keys[_keys.Count - 1].Add(msg);}// 從新記錄輸入內容 else{_keys.Add(new List<EventMsg>());_keys[_keys.Count - 1].Add(msg);_result.Add(string.Empty);}#endregion_last = DateTime.Now;#region 獲取鍵盤狀態// 記錄正在按下的按鍵 if (msg.paramH == 0 && !_keydown.Contains(msg.message)){_keydown.Add(msg.message);}// 清除已松開的按鍵 if (msg.paramH > 0 && _keydown.Contains(msg.message)){_keydown.Remove(msg.message);}#endregion#region 計算按鍵信息int v = msg.message & 0xff;int c = msg.paramL & 0xff;StringBuilder strKeyName = new StringBuilder(500);if (GetKeyNameText(c * 65536, strKeyName, 255) > 0){_key = strKeyName.ToString().Trim(new char[] { ' ', '\0' });GetKeyboardState(_state);if (_key.Length == 1 && msg.paramH == 0)// && msg.paramH == 0{// 根據鍵盤狀態和shift緩存判斷輸出字符 _cur = ShiftChar(_key, isShift, _state).ToString();_result[_result.Count - 1] += _cur;} // 備選 else{_cur = string.Empty;}}#endregion}private char ShiftChar(string k, bool isShiftDown, byte[] state){bool capslock = state[0x14] == 1;bool numlock = state[0x90] == 1;bool scrolllock = state[0x91] == 1;bool shiftdown = state[0xa0] == 1;char chr = (capslock ? k.ToUpper() : k.ToLower()).ToCharArray()[0];if (isShiftDown){if (chr >= 'a' && chr <= 'z'){chr = (char)((int)chr - 32);}else if (chr >= 'A' && chr <= 'Z'){if (chr == 'Z'){string s = "";}chr = (char)((int)chr + 32);}else{string s = "`1234567890-=[];',./";string u = "~!@#$%^&*()_+{}:\"<>?";if (s.IndexOf(chr) >= 0){return (u.ToCharArray())[s.IndexOf(chr)];}}}return chr;}}public struct EventMsg{public int message;public int paramL;public int paramH;public int Time;public int hwnd;}} }上面是獲取掃碼槍掃描數據的具體代碼,掃描過快的話會導致條碼粘連,不過因為條碼長度都一樣,所以可以獲取數據后再進行加工處理。下面是獲取數據后并處理的過程
using System; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Collections; using System.Collections.Generic; namespace WindowsFormsApplication6 {public partial class Form1 : Form{private ScanerHook listener = new ScanerHook();KeyboardHook k_hook;public Form1(){InitializeComponent();listener.ScanerEvent += Listener_ScanerEvent;k_hook = new KeyboardHook();k_hook.KeyDownEvent += K_hook_KeyDownEvent;k_hook.Start();}HashSet<string> set = new HashSet<string>();int count = 0;private void Listener_ScanerEvent(ScanerHook.ScanerCodes codes){count++;DataGridViewRow row = new DataGridViewRow();int index = dataGridView1.Rows.Add(row);int i = dataGridView1.Rows.Count - 1;dataGridView1.CurrentCell = dataGridView1[0, i];dataGridView1.Rows[i].Selected = true;dataGridView1.FirstDisplayedCell = dataGridView1.Rows[i].Cells[0];dataGridView1.Rows[index].Cells[0].Value= codes.Result.ToUpper();// System.Console.WriteLine(codes.Result.ToUpper());if (codes.Result.ToUpper().Length % 14 == 0) { if (!set.Contains(codes.Result.ToUpper())){int h = 14;int k = codes.Result.ToUpper().Length;string n = codes.Result.ToUpper();if (k >= 14){int m = k / h;for (int x = 0; x < m; x++){int t = x * h;string b = n.Substring(t, h);set.Add(b);}}}}label1.Text ="有效數量:"+ set.Count.ToString();label2.Text = "縂數量:" +count;}private void Form1_Load(object sender, EventArgs e){listener.Start();}private void K_hook_KeyDownEvent(object sender, KeyEventArgs e){if (e.KeyCode == Keys.F4){SendMsg sendMsg = new SendMsg();foreach(Object s in set){sendMsg.SendText(s+"\r");}// sendMsg.SendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss\r"));if(MessageBox.Show("do you?","Confirm Message", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK){set.Clear();dataGridView1.Rows.Clear();label1.Text = "有效數量:0";label2.Text = "縂數量:0";count = 0;}}}private void button1_Click(object sender, EventArgs e){set.Clear();dataGridView1.Rows.Clear();label1.Text = "有效數量:0";label2.Text = "縂數量:0";count = 0;}}internal class SendMsg{[DllImport("user32.dll")]public static extern IntPtr GetForegroundWindow();[DllImport("user32.dll", CharSet = CharSet.Auto)]public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);[DllImport("user32.dll")]static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);[DllImport("user32.dll")]static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);[StructLayout(LayoutKind.Sequential)]public struct GUITHREADINFO{public int cbSize;public int flags;public IntPtr hwndActive;public IntPtr hwndFocus;public IntPtr hwndCapture;public IntPtr hwndMenuOwner;public IntPtr hwndMoveSize;public IntPtr hwndCaret;public RECT rectCaret;}[StructLayout(LayoutKind.Sequential)]public struct RECT{int left;int top;int right;int bottom;}public GUITHREADINFO? GetGuiThreadInfo(IntPtr hwnd){if (hwnd != IntPtr.Zero){uint threadId = GetWindowThreadProcessId(hwnd, IntPtr.Zero);GUITHREADINFO guiThreadInfo = new GUITHREADINFO();guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo);if (GetGUIThreadInfo(threadId, ref guiThreadInfo) == false)return null;return guiThreadInfo;}return null;}public void SendText(string text){IntPtr hwnd = GetForegroundWindow();if (String.IsNullOrEmpty(text))return;GUITHREADINFO? guiInfo = GetGuiThreadInfo(hwnd);if (guiInfo != null){for (int i = 0; i < text.Length; i++){SendMessage(guiInfo.Value.hwndFocus, 0x0102, (IntPtr)(int)text[i], IntPtr.Zero);}}}}internal class KeyboardHook{public event KeyEventHandler KeyDownEvent;public event KeyPressEventHandler KeyPressEvent;public event KeyEventHandler KeyUpEvent;public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);static int hKeyboardHook = 0; //聲明鍵盤鉤子處理的初始值//值在Microsoft SDK的Winuser.h里查詢public const int WH_KEYBOARD_LL = 13; //線程鍵盤鉤子監聽鼠標消息設為2,全局鍵盤監聽鼠標消息設為13HookProc KeyboardHookProcedure; //聲明KeyboardHookProcedure作為HookProc類型//鍵盤結構[StructLayout(LayoutKind.Sequential)]public class KeyboardHookStruct{public int vkCode; //定一個虛擬鍵碼。該代碼必須有一個價值的范圍1至254public int scanCode; // 指定的硬件掃描碼的關鍵public int flags; // 鍵標志public int time; // 指定的時間戳記的這個訊息public int dwExtraInfo; // 指定額外信息相關的信息}//使用此功能,安裝了一個鉤子[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);//調用此函數卸載鉤子[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]public static extern bool UnhookWindowsHookEx(int idHook);//使用此功能,通過信息鉤子繼續下一個鉤子[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);// 取得當前線程編號(線程鉤子需要用到)[DllImport("kernel32.dll")]static extern int GetCurrentThreadId();//使用WINDOWS API函數代替獲取當前實例的函數,防止鉤子失效[DllImport("kernel32.dll")]public static extern IntPtr GetModuleHandle(string name);public void Start(){// 安裝鍵盤鉤子if (hKeyboardHook == 0){KeyboardHookProcedure = new HookProc(KeyboardHookProc);hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0);//hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);//************************************//鍵盤線程鉤子SetWindowsHookEx(13, KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());//指定要監聽的線程idGetCurrentThreadId(),//鍵盤全局鉤子,需要引用空間(using System.Reflection;)//SetWindowsHookEx( 13,MouseHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);////關于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函數將鉤子加入到鉤子鏈表中,說明一下四個參數://idHook 鉤子類型,即確定鉤子監聽何種消息,上面的代碼中設為2,即監聽鍵盤消息并且是線程鉤子,如果是全局鉤子監聽鍵盤消息應設為13,//線程鉤子監聽鼠標消息設為7,全局鉤子監聽鼠標消息設為14。lpfn 鉤子子程的地址指針。如果dwThreadId參數為0 或是一個由別的進程創建的//線程的標識,lpfn必須指向DLL中的鉤子子程。 除此以外,lpfn可以指向當前進程的一段鉤子子程代碼。鉤子函數的入口地址,當鉤子鉤到任何//消息后便調用這個函數。hInstance應用程序實例的句柄。標識包含lpfn所指的子程的DLL。如果threadId 標識當前進程創建的一個線程,而且子//程代碼位于當前進程,hInstance必須為NULL??梢院芎唵蔚脑O定其為本應用程序的實例句柄。threaded 與安裝的鉤子子程相關聯的線程的標識符//如果為0,鉤子子程與所有的線程關聯,即為全局鉤子//************************************//如果SetWindowsHookEx失敗if (hKeyboardHook == 0){// Stop();throw new Exception("安裝鍵盤鉤子失敗");}}}public void Stop(){bool retKeyboard = true;if (hKeyboardHook != 0){retKeyboard = UnhookWindowsHookEx(hKeyboardHook);hKeyboardHook = 0;}try{if (!(retKeyboard)){// throw new Exception("卸載鉤子失敗!");}}catch (Exception){throw;}// if (!(retKeyboard)) throw new Exception("卸載鉤子失敗!");}//ToAscii職能的轉換指定的虛擬鍵碼和鍵盤狀態的相應字符或字符[DllImport("user32")]public static extern int ToAscii(int uVirtKey, //[in] 指定虛擬關鍵代碼進行翻譯。int uScanCode, // [in] 指定的硬件掃描碼的關鍵須翻譯成英文。高階位的這個值設定的關鍵,如果是(不壓)byte[] lpbKeyState, // [in] 指針,以256字節數組,包含當前鍵盤的狀態。每個元素(字節)的數組包含狀態的一個關鍵。如果高階位的字節是一套,關鍵是下跌(按下)。在低比特,如果設置表明,關鍵是對切換。在此功能,只有肘位的CAPS LOCK鍵是相關的。在切換狀態的NUM個鎖和滾動鎖定鍵被忽略。byte[] lpwTransKey, // [out] 指針的緩沖區收到翻譯字符或字符。int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.//獲取按鍵的狀態[DllImport("user32")]public static extern int GetKeyboardState(byte[] pbKeyState);[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]private static extern short GetKeyState(int vKey);private const int WM_KEYDOWN = 0x100;//KEYDOWNprivate const int WM_KEYUP = 0x101;//KEYUPprivate const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWNprivate const int WM_SYSKEYUP = 0x105;//SYSKEYUPprivate int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam){// 偵聽鍵盤事件if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null)){KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));// raise KeyDownif (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)){Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;KeyEventArgs e = new KeyEventArgs(keyData);KeyDownEvent(this, e);}//鍵盤按下if (KeyPressEvent != null && wParam == WM_KEYDOWN){byte[] keyState = new byte[256];GetKeyboardState(keyState);byte[] inBuffer = new byte[2];if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1){KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);KeyPressEvent(this, e);}}// 鍵盤抬起if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)){Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;KeyEventArgs e = new KeyEventArgs(keyData);KeyUpEvent(this, e);}}//如果返回1,則結束消息,這個消息到此為止,不再傳遞。//如果返回0或調用CallNextHookEx函數則消息出了這個鉤子繼續往下傳遞,也就是傳給消息真正的接受者return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);}~KeyboardHook(){Stop();}} } 部分代碼引用源文連接:[源文鏈接,如有侵權請聯系刪除(https://blog.csdn.net/baidu_19356259/article/details/121998523)
總結
以上是生活随笔為你收集整理的C#获取扫码枪扫描数据并处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: androidx.preference.
- 下一篇: PDK文件学习