Windows下用C# .NET7实现后台读取条码扫描器数据问询
解决方案说明
一、浏览器JavaScript无法实现需求
- 浏览器的安全沙箱限制了JS直接访问系统硬件或拦截全局输入事件,即便输入框设置了
autofocus,只要浏览器不是前台窗口,系统就会将键盘输入导向当前活跃的前台应用,JS完全无法捕获后台状态下的USB设备输入。 - 因此必须依赖桌面端程序实现后台输入拦截与转发。
二、基于C# .NET7的可行方案
针对你的场景,推荐使用RawInput API结合后台服务/系统托盘应用的方案,以下是具体实现思路:
1. RawInput API的C#封装与使用
RawInput可直接识别特定USB设备的输入,不会被前台窗口抢占,核心步骤:
- 通过P/Invoke封装RawInput相关Win32 API(如
RegisterRawInputDevices、GetRawInputData等)。 - 注册监听目标USB条码扫描器(通过设备的VID/PID筛选,避免捕获普通键盘输入)。
- 在后台隐藏窗口中处理RawInput消息,解析条码数据。
- 解析完成后,通过HTTP请求将条码数据发送到
/authenticate接口,替代浏览器表单提交逻辑。
2. 后台运行的实现方式
- 系统托盘应用:用.NET7的Windows Forms或WPF创建带托盘图标的应用,启动后隐藏主窗口,在后台监听RawInput事件,适合需要用户交互(如设置设备、查看日志)的场景。
- Windows服务+辅助进程:纯服务无法直接处理RawInput(无交互桌面权限),需配合
CreateProcessAsUser启动带桌面交互的辅助进程监听输入,适合完全无界面的后台运行场景。
3. 关键代码片段示例
(1)RawInput基础P/Invoke定义
using System.Runtime.InteropServices; public static class RawInputNative { [StructLayout(LayoutKind.Sequential)] public struct RAWINPUTDEVICE { public ushort UsagePage; public ushort Usage; public uint Flags; public IntPtr WindowHandle; } [DllImport("user32.dll", SetLastError = true)] public static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevices, uint uiNumDevices, uint cbSize); // 需补充封装GetRawInputData、GetRawInputDeviceInfo等必要API }
(2)注册目标条码扫描器
假设扫描器属于HID键盘类(Usage Page=0x01,Usage=0x06),通过VID/PID筛选设备:
// 先实现GetTargetScannerHandle方法,根据VID/PID找到目标设备句柄 IntPtr targetWindowHandle = GetHiddenWindowHandle(); // 后台隐藏窗口的句柄 var rid = new RAWINPUTDEVICE[] { new RAWINPUTDEVICE { UsagePage = 0x01, Usage = 0x06, Flags = 0x00000001 | 0x00000010, // RIDEV_INPUTSINK + RIDEV_DEVNOTIFY WindowHandle = targetWindowHandle } }; RawInputNative.RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICE)));
(3)处理RawInput消息
在隐藏窗口的WndProc中捕获WM_INPUT消息并解析条码:
protected override void WndProc(ref Message m) { const int WM_INPUT = 0x00FF; if (m.Msg == WM_INPUT) { string barcode = ParseRawInputData(m.LParam); // 实现解析按键序列为条码的逻辑 if (!string.IsNullOrEmpty(barcode)) { using var client = new HttpClient(); var content = new FormUrlEncodedContent(new Dictionary<string, string> { { "BarCode", barcode } }); _ = client.PostAsync("http://your-server-address/authenticate", content); } } base.WndProc(ref m); }
三、替代方案:WH_KEYBOARD_LL全局钩子
如果RawInput的设备筛选存在困难,可使用WH_KEYBOARD_LL钩子:
- 全局捕获键盘输入,通过扫描器的输入特征(如连续快速按键、结尾带回车)判断是否为目标条码。
- 钩子需在有消息循环的进程中运行,系统托盘应用是合适载体,通过
SetWindowsHookEx等P/Invoke实现。
内容的提问来源于stack exchange,提问作者Andrus
相关产品推荐
相关产品推荐

