使用wpf应用程序读取条形码

2024-01-13

在我的一个 WPF 应用程序中,我需要能够使用 C# 读取条形码值。我不知道该怎么做。任何帮助,将不胜感激。

提前致谢。


最好的方法是创建一个键盘钩子。

下面是我在几个项目中使用过的一个类。

你像这样使用它:

var hook = new KeyboardHook();
var availbleScanners = KeyboardHook.GetKeyboardDevices();
... // find out which scanner to use 

hook.SetDeviceFilter(availableScanners.First());

hook.KeyPressed += OnBarcodeKey;

hook.AddHook(YourWPFMainView);

...

public void OnBarcodeKey(object sender, KeyPressedEventArgs e) {
    Console.WriteLine("received " + e.Text);
}

我从那里得到了低级键盘的东西本文 http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/.

  public class KeyPressedEventArgs : EventArgs
  {

    public KeyPressedEventArgs(string text) {
      mText = text;
    }
    public string Text { get { return mText; } }

    private readonly string mText;
  }

  public partial class KeyboardHook 
    : IDisposable
  {
    private static readonly Regex DeviceNamePattern = new Regex(@"#([^#]+)");
    public event EventHandler<KeyPressedEventArgs> KeyPressed;

    /// <summary>
    /// Set the device to use in keyboard hook
    /// </summary>
    /// <param name="deviceId">Name of device</param>
    /// <returns>true if device is found</returns>
    public bool SetDeviceFilter(string deviceId) {
      Dictionary<string, IntPtr> devices = FindAllKeyboardDevices();
      return devices.TryGetValue(deviceId, out mHookDeviceId);
    }

    /// <summary>
    /// Add this KeyboardHook to a window
    /// </summary>
    /// <param name="window">The window to add to</param>
    public void AddHook(System.Windows.Window window) {
      if (window == null)
        throw new ArgumentNullException("window");
      if (mHwndSource != null)
        throw new InvalidOperationException("Hook already present");

      IntPtr hwnd = new WindowInteropHelper(window).Handle;
      mHwndSource = HwndSource.FromHwnd(hwnd);
      if (mHwndSource == null)
        throw new ApplicationException("Failed to receive window source");

      mHwndSource.AddHook(WndProc);

      RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];

      rid[0].usUsagePage = 0x01;
      rid[0].usUsage = 0x06;
      rid[0].dwFlags = RIDEV_INPUTSINK;
      rid[0].hwndTarget = hwnd;

      if (!RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0])))
        throw new ApplicationException("Failed to register raw input device(s).");
    }

    /// <summary>
    /// Remove this keyboard hook from window (if it is added)
    /// </summary>
    public void RemoveHook() {
      if (mHwndSource == null)
        return; // not an error

      RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];

      rid[0].usUsagePage = 0x01;
      rid[0].usUsage = 0x06;
      rid[0].dwFlags = 0x00000001;
      rid[0].hwndTarget = IntPtr.Zero;

      RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));
      mHwndSource.RemoveHook(WndProc);
      mHwndSource.Dispose();
      mHwndSource = null;
    }

    public void Dispose() {
      RemoveHook();
    }

    private IntPtr mHookDeviceId;
    private HwndSource mHwndSource;

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
      switch (msg) {
        case WM_INPUT: 
          if (ProcessInputCommand(mHookDeviceId, lParam)) {
            MSG message;
            PeekMessage(out message, IntPtr.Zero, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
          }
          break;
      }
      return IntPtr.Zero;
    }

    /// <summary>
    /// Get a list of keyboard devices available
    /// </summary>
    /// <returns>Collection of devices available</returns>
    public static ICollection<string> GetKeyboardDevices() {
      return FindAllKeyboardDevices().Keys;
    }

    private static Dictionary<string, IntPtr> FindAllKeyboardDevices() {
      Dictionary<string, IntPtr> deviceNames = new Dictionary<string, IntPtr>();
      uint deviceCount = 0;
      int dwSize = (Marshal.SizeOf(typeof(RAWINPUTDEVICELIST)));

      if (GetRawInputDeviceList(IntPtr.Zero, ref deviceCount, (uint)dwSize) == 0) {
        IntPtr pRawInputDeviceList = Marshal.AllocHGlobal((int)(dwSize*deviceCount));

        try {
          GetRawInputDeviceList(pRawInputDeviceList, ref deviceCount, (uint)dwSize);

          for (int i = 0; i < deviceCount; i++) {
            uint pcbSize = 0;

            var rid = (RAWINPUTDEVICELIST)Marshal.PtrToStructure(
                                            new IntPtr((pRawInputDeviceList.ToInt32() + (dwSize*i))),
                                            typeof(RAWINPUTDEVICELIST));

            GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, IntPtr.Zero, ref pcbSize);

            if (pcbSize > 0) {
              IntPtr pData = Marshal.AllocHGlobal((int)pcbSize);
              try {
                GetRawInputDeviceInfo(rid.hDevice, RIDI_DEVICENAME, pData, ref pcbSize);
                string deviceName = Marshal.PtrToStringAnsi(pData);

                // The list will include the "root" keyboard and mouse devices
                // which appear to be the remote access devices used by Terminal
                // Services or the Remote Desktop - we're not interested in these
                // so the following code with drop into the next loop iteration
                if (deviceName.ToUpper().Contains("ROOT"))
                  continue;

                // If the device is identified as a keyboard or HID device,
                // Check if it is the one we're looking for
                if (rid.dwType == RIM_TYPEKEYBOARD || rid.dwType == RIM_TYPEHID) {
                  Match match = DeviceNamePattern.Match(deviceName);
                  if (match.Success)
                    deviceNames.Add(match.Groups[1].Value, rid.hDevice);
                }
              }
              finally {
                Marshal.FreeHGlobal(pData);
              }
            }
          }
        }
        finally {
          Marshal.FreeHGlobal(pRawInputDeviceList);
        }
      }
      return deviceNames;
    }

    /// <summary>
    /// Processes WM_INPUT messages to retrieve information about any
    /// keyboard events that occur.
    /// </summary>
    /// <param name="deviceId">Device to process</param>
    /// <param name="lParam">The WM_INPUT message to process.</param>
    private bool ProcessInputCommand(IntPtr deviceId, IntPtr lParam) {
      uint dwSize = 0;

      try {
        // First call to GetRawInputData sets the value of dwSize
        // dwSize can then be used to allocate the appropriate amount of memory,
        // storing the pointer in "buffer".
        GetRawInputData(lParam, RID_INPUT, IntPtr.Zero,ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));

        IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);
        try {
          // Check that buffer points to something, and if so,
          // call GetRawInputData again to fill the allocated memory
          // with information about the input
          if (buffer != IntPtr.Zero &&
              GetRawInputData(lParam, RID_INPUT, buffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) == dwSize) {
            // Store the message information in "raw", then check
            // that the input comes from a keyboard device before
            // processing it to raise an appropriate KeyPressed event.

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

            if (raw.header.hDevice != deviceId)
              return false;

            if (raw.header.dwType != RIM_TYPEKEYBOARD)
              return false;
            if (raw.keyboard.Message != WM_KEYDOWN && raw.keyboard.Message != WM_SYSKEYDOWN)
              return false;

            // On most keyboards, "extended" keys such as the arrow or page 
            // keys return two codes - the key's own code, and an "extended key" flag, which
            // translates to 255. This flag isn't useful to us, so it can be
            // disregarded.
            if (raw.keyboard.VKey > VK_LAST_KEY)
              return false;

            if (KeyPressed != null) {
              string scannedText = null;
              lock (mLocalBuffer) {
                if (GetKeyboardState(mKeyboardState)) {
                  if (ToUnicode(raw.keyboard.VKey, raw.keyboard.MakeCode, mKeyboardState, mLocalBuffer, 64, 0) > 0) {
                    if (mLocalBuffer.Length > 0) {
                      scannedText = mLocalBuffer.ToString();
                    }
                  }
                }
              }
              if (!string.IsNullOrEmpty(scannedText))
                KeyPressed(this, new KeyPressedEventArgs(scannedText));
            }
            return true;
          }
        }
        finally {
          Marshal.FreeHGlobal(buffer);
        }
      }
      catch (Exception err) {
        Logger.LogError(err, "Scanner error");
      }
      return false;
    }
    private static readonly StringBuilder mLocalBuffer = new StringBuilder();
    private static readonly byte[] mKeyboardState = new byte[256];
  } 

 public partial class KeyboardHook
  {
    private const int RIDEV_INPUTSINK = 0x00000100;
    private const int RIDEV_REMOVE = 0x00000001;
    private const int RID_INPUT = 0x10000003;

    private const int FAPPCOMMAND_MASK = 0xF000;
    private const int FAPPCOMMAND_MOUSE = 0x8000;
    private const int FAPPCOMMAND_OEM = 0x1000;

    private const int RIM_TYPEMOUSE = 0;
    private const int RIM_TYPEKEYBOARD = 1;
    private const int RIM_TYPEHID = 2;

    private const int RIDI_DEVICENAME = 0x20000007;

    private const int WM_KEYDOWN = 0x0100;
    private const int WM_SYSKEYDOWN = 0x0104;
    private const int WM_INPUT = 0x00FF;
    private const int VK_OEM_CLEAR = 0xFE;
    private const int VK_LAST_KEY = VK_OEM_CLEAR; // this is a made up value used as a sentinal

    private const int PM_REMOVE = 0x01;

    [StructLayout(LayoutKind.Sequential)]
    private struct RAWINPUTDEVICELIST
    {
      public IntPtr hDevice;

      [MarshalAs(UnmanagedType.U4)]
      public int dwType;
    }

    [StructLayout(LayoutKind.Explicit)]
    private struct RAWINPUT
    {
      [FieldOffset(0)]
      public RAWINPUTHEADER header;

      [FieldOffset(16)]
      public RAWMOUSE mouse;

      [FieldOffset(16)]
      public RAWKEYBOARD keyboard;

      [FieldOffset(16)]
      public RAWHID hid;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct RAWINPUTHEADER
    {
      [MarshalAs(UnmanagedType.U4)]
      public int dwType;

      [MarshalAs(UnmanagedType.U4)]
      public int dwSize;

      public IntPtr hDevice;

      [MarshalAs(UnmanagedType.U4)]
      public int wParam;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct RAWHID
    {
      [MarshalAs(UnmanagedType.U4)]
      public int dwSizHid;

      [MarshalAs(UnmanagedType.U4)]
      public int dwCount;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct BUTTONSSTR
    {
      [MarshalAs(UnmanagedType.U2)]
      public ushort usButtonFlags;

      [MarshalAs(UnmanagedType.U2)]
      public ushort usButtonData;
    }

    [StructLayout(LayoutKind.Explicit)]
    private struct RAWMOUSE
    {
      [MarshalAs(UnmanagedType.U2)]
      [FieldOffset(0)]
      public ushort usFlags;

      [MarshalAs(UnmanagedType.U4)]
      [FieldOffset(4)]
      public uint ulButtons;

      [FieldOffset(4)]
      public BUTTONSSTR buttonsStr;

      [MarshalAs(UnmanagedType.U4)]
      [FieldOffset(8)]
      public uint ulRawButtons;

      [FieldOffset(12)]
      public int lLastX;

      [FieldOffset(16)]
      public int lLastY;

      [MarshalAs(UnmanagedType.U4)]
      [FieldOffset(20)]
      public uint ulExtraInformation;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct RAWKEYBOARD
    {
      [MarshalAs(UnmanagedType.U2)]
      public ushort MakeCode;

      [MarshalAs(UnmanagedType.U2)]
      public ushort Flags;

      [MarshalAs(UnmanagedType.U2)]
      public ushort Reserved;

      [MarshalAs(UnmanagedType.U2)]
      public ushort VKey;

      [MarshalAs(UnmanagedType.U4)]
      public uint Message;

      [MarshalAs(UnmanagedType.U4)]
      public uint ExtraInformation;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct RAWINPUTDEVICE
    {
      [MarshalAs(UnmanagedType.U2)]
      public ushort usUsagePage;

      [MarshalAs(UnmanagedType.U2)]
      public ushort usUsage;

      [MarshalAs(UnmanagedType.U4)]
      public int dwFlags;

      public IntPtr hwndTarget;
    }

    [DllImport("User32.dll")]
    private static extern uint GetRawInputDeviceList(IntPtr pRawInputDeviceList, ref uint uiNumDevices, uint cbSize);

    [DllImport("User32.dll")]
    private static extern uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);

    [DllImport("User32.dll")]
    private static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);

    [DllImport("User32.dll")]
    private static extern uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);

    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetKeyboardState(byte[] lpKeyState);
    [DllImport("user32.dll")]
    private static extern int ToUnicode(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr, SizeConst = 64)] StringBuilder pwszBuff,
                                         int cchBuff, uint wFlags);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool PeekMessage(out MSG lpmsg, IntPtr hwnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用wpf应用程序读取条形码 的相关文章

随机推荐

  • “未绑定到有效相机”CameraX 错误

    我试图遵循谷歌的 CameraX入门 代码实验室 我尝试用Java而不是Kotlin来完成它 但是当我运行它并尝试拍照时 它给了我一个错误 说未绑定到有效的相机 我在代码中找不到错误所在 我检查了 logcat 它说表面可能存在问题 它可能
  • 检测实际的形式变化?

    是否有一种现成的方法 也许在一个框架中 来检测表单是否具有changed与其原始值相比 onchange 事件不会执行 因为无论实际更改如何 它都会触发 例如 我可以使用两个 onchange 事件勾选一个复选框 然后再次关闭 最后的手段是
  • 索引布尔列与日期时间列的查询性能

    如果索引设置为datetime键入列 而不是boolean输入列 并且查询是在该列上完成的 在我当前的设计中 我有两列 is active小整数 1 indexed deleted at约会时间 查询是SELECT FROM table W
  • 选择哪个 log4j 门面?

    本质上 我正在寻找与 log4j 具有相同行为 配置 日志记录级别的东西 但缺少一些功能 例如格式化日志记录 请参阅here https stackoverflow com questions 920458 and here https s
  • 如何在 Xcode 中使用 cocos2d?

    我下载了最新版本的 cocos2d 但我对如何在当前项目中使用它感到困惑 谁能告诉我如何在 xcode 中使用它 我正在设计一个二维迷宫 我必须进口一些东西吗 任何形式的帮助将不胜感激 是的 您需要将cocos2d文件拖到您的项目中 然后它
  • boost.org 的 Spirit 解析器生成器框架有哪些缺点?

    在几个问题中我看到了以下建议Spirit http www boost org doc libs 1 37 0 libs spirit classic index html解析器生成器框架来自boost org http www boost
  • ClassCastException:android.app.Application

    导致错误的类如下 package com extrasmart import android app Activity import android os Bundle import android view View import and
  • 真正可复制的 Docker 容器?

    有一种安全趋势叫做可重复的构建 https en wikipedia org wiki Reproducible builds 其目标是有一种方法来创建输出二进制文件的位精确副本 以便用户可以验证在互联网上找到的版本是否值得信赖 Docke
  • 如何测试 ColdFusion 结构中是否存在变量?

    我想测试一下
  • Microsoft Graph 访问令牌刷新

    我正在编写一个应用程序 该应用程序使用 OAuth 2 0 客户端凭据授予流程 来获取用于调用 Microsoft Graph API 的访问令牌 应用程序以自身身份进行身份验证 而不是代表登录用户进行身份验证 我的代码基于此来自微软的例子
  • 如何在 pdb 中等待协程

    我正在使用异步库 asyncpg https github com MagicStack asyncpg 并且我想调试一些异步调用来查询数据库 我放置了一个 pdb 断点并想尝试一些查询 pdb await asyncpg fetch se
  • 提交表单时将输入文本转换为小写

    我有一个表单 其中有一个文本字段配有提交按钮 单击提交按钮后 它会从第一个 php 页面重定向到第二个 php 页面 索引 php
  • 使用现有的持久卷声明部署 bitnami/mysql helm 图表

    我正在尝试部署比特纳米 mysql https github com bitnami charts tree master bitnami mysql我里面的图表minikube https minikube sigs k8s io doc
  • 服务器启动时执行的内容与请求传入时执行的内容是什么?

    我一直在 Django 中进行一些类黑客攻击 我从 settings py 中调用我的更改 因为我认为它会先于其他任何事情运行 然而 我刚刚遇到了一种情况 这对我不起作用 那么 还有其他地方吗aftersettings py 我可以保证服务
  • 将 TrueType 字体加载到 OpenCV

    我们可以加载自定义 TrueType 字体并将其与cv2 putText功能 font cv2 FONT HERSHEY SIMPLEX cv2 putText img OpenCV 10 500 font 4 255 255 255 2
  • 无效方差:类型参数“T”在“xxx.IItem.GetList()”上必须始终有效。 “T”是协变的[重复]

    这个问题在这里已经有答案了 为什么下面的代码会出现错误 无效方差 类型参数 T 必须始终有效 UserQuery IItem GetList T 是协变的 public interface IFoo public interface IBa
  • 如何使用java代码调用solr进行优化

    不在壳下 我想使用 Java 代码调用优化并在优化过程完成时收到通知 只需发出请求即可 solr update optimize true从任何可以访问 Solr 服务器的地方 任何东西 例如 curl http localhost 898
  • 如何像 MS Access 一样使用目录路径连接 MySQL 数据库文件(.sql)?

    抱歉 也许这是我第二次问这个问题 因为没有得到任何答案 这是我的代码 try File f new File Database sql if f exists Class forName com mysql jdbc Driver newI
  • 您如何思考并预测这样的线程问题的输出?

    我正在准备 SCJP 多线程一直是我最不稳定的领域 主要是因为我不知道如何查看多线程代码并逐步完成它 到目前为止 我的方法是用英语写下每个线程中可能发生的情况 并测试一些线程随机交叉的情况 这确实是一种偶然且耗时的方法 所以我想看看专业人士
  • 使用wpf应用程序读取条形码

    在我的一个 WPF 应用程序中 我需要能够使用 C 读取条形码值 我不知道该怎么做 任何帮助 将不胜感激 提前致谢 最好的方法是创建一个键盘钩子 下面是我在几个项目中使用过的一个类 你像这样使用它 var hook new Keyboard