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

本文关键字:条形码 读取 应用程序 wpf 使用 | 更新日期: 2023-09-27 18:08:08

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

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

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

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

你可以这样使用:

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);
}

我从这篇文章中得到了低级键盘的东西。

  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);
  }
}

我见过的大多数条形码阅读器都模拟键盘并发送按键流,然后发送回车。

如果您的条形码阅读器以这种方式工作,那么常规编辑框应该可以工作。