Reading bar codes using wpf application - c#

In one of my WPF applications, I have the need to be able to read bar code values using C#. I am not sure how to do this. Any help would be appreciated.
Thanks in advance.

The best way is to create a keyboard hook.
Below is a class that I have used in several projects.
You use it like this:
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);
}
I got the low level keyboard stuff from this article.
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);
}
}

Most of the barcode readers I've seen emulate a keyboard and send a key-press stream followed by a carriage return.
If your barcode reader works this way then a regular edit box should work.

Related

ContextMenu on NotifyIcon with C# and Windows CE

I have a C# application running on Windows CE 6.0 with CF 3.5, I think. The application starts minimized in the system tray with an icon. It's working so far but now I want to add context menu to this icon and I really don't get behind the secret with this context menu. The Icon is created with this code:
public event EventHandler Click;
private MyMessageWindow messageWindow;
private int uID = 5000;
private System.Drawing.Icon m_Icon;
public NotifyIcon()
{
messageWindow = new MyMessageWindow(this);
messageWindow.uID = uID;
}
public System.Drawing.Icon Icon
{
set { m_Icon = value; }
}
~NotifyIcon()
{
Remove();
}
public void Add(IntPtr hIcon)
{
NotifyMessage(messageWindow.Hwnd, NIM_ADD, (uint) uID, hIcon);
}
public void Add(string IconRes)
{
IntPtr hIcon = LoadIcon(GetModuleHandle(null), IconRes);
NotifyMessage(messageWindow.Hwnd, NIM_ADD, (uint) uID, hIcon);
}
public void Add(System.Drawing.Icon icon)
{
NotifyMessage(messageWindow.Hwnd, NIM_ADD, (uint) uID, icon.Handle);
}
public void Add()
{
if (m_Icon != null)
{
NotifyMessage(messageWindow.Hwnd, NIM_ADD, (uint) uID, m_Icon.Handle);
}
}
public void Remove()
{
NotifyMessage(messageWindow.Hwnd, NIM_DELETE, (uint) uID, IntPtr.Zero);
}
public void Modify(IntPtr hIcon)
{
NotifyMessage(messageWindow.Hwnd, NIM_MODIFY, (uint) uID, hIcon);
}
private void NotifyMessage(IntPtr hwnd, int dwMessage, uint uID, IntPtr hIcon)
{
NOTIFYICONDATA notdata = new NOTIFYICONDATA();
notdata.cbSize = 152;
notdata.hIcon = hIcon;
notdata.hWnd = hwnd;
notdata.uCallbackMessage = WM_NOTIFY_TRAY;
notdata.uFlags = NIF_MESSAGE | NIF_ICON;
notdata.uID = uID;
int ret = Shell_NotifyIcon(dwMessage, ref notdata);
}
//Definition of the message.
private const int NIF_MESSAGE = 0x00000001;
private const int NIF_ICON = 0x00000002;
internal const int WM_LBUTTONDOWN = 0x0201;
internal const int NIM_ADD = 0x00000000;
internal const int NIM_MODIFY = 0x00000001;
internal const int NIM_DELETE = 0x00000002;
//Custom message
internal const int WM_NOTIFY_TRAY = 0x0400 + 2001;
internal struct NOTIFYICONDATA
{
internal int cbSize;
internal IntPtr hWnd;
internal uint uID;
internal uint uFlags;
internal uint uCallbackMessage;
internal IntPtr hIcon;
}
[DllImport("coredll.dll")]
internal static extern int Shell_NotifyIcon(
int dwMessage, ref NOTIFYICONDATA pnid);
[DllImport("coredll.dll")]
internal static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("coredll.dll")]
internal static extern int ShowWindow(
IntPtr hWnd,
int nCmdShow);
[DllImport("coredll.dll")]
internal static extern IntPtr GetFocus();
[DllImport("coredll.dll")]
internal static extern IntPtr LoadIcon(IntPtr hInst, string IconName);
[DllImport("coredll.dll")]
internal static extern IntPtr GetModuleHandle(String lpModuleName);
#endregion
#region MessageWindow
internal class MyMessageWindow : Microsoft.WindowsCE.Forms.MessageWindow
{
private int _uID = 0;
private NotifyIcon notifyIcon;
public MyMessageWindow(NotifyIcon notIcon)
{
notifyIcon = notIcon;
}
public int uID
{
set { _uID = value; }
}
protected override void WndProc(ref Microsoft.WindowsCE.Forms.Message msg)
{
if (msg.Msg == WM_NOTIFY_TRAY)
{
if ((int) msg.LParam == WM_LBUTTONDOWN)
{
if ((int) msg.WParam == _uID)
{
if (notifyIcon.Click != null)
notifyIcon.Click(notifyIcon, null);
}
}
}
}
}
I know windows CE is not state of the art but I need to do this because of old hardware.

Simulate keyboard click in GTA:SA

I'm trying to run a program that sometimes will simulate clicks in GTA:SA. Problem is it doesn't do anything when running. I have tried this code so far:
IntPtr calculatorHandle = FindWindow(null, "GTA:SA:MP");
if (calculatorHandle == IntPtr.Zero)
{
MessageBox.Show("GTA:SA:MP isn't running");
return;
}
SetForegroundWindow(calculatorHandle);
SendKeys.SendWait("T123");
I'd be glad if you tell if something is wrong with my code. Thanks!
EDIT
This is my code after adding Neill's code:
IntPtr calculatorHandle = FindWindow(null, "GTA:SA:MP");
if (calculatorHandle == IntPtr.Zero)
{
MessageBox.Show("GTA:SA:MP isn't running");
return;
}
SetForegroundWindow(calculatorHandle);
short key = 0x14;
WindowsMessageService.SendKey(key, KeyFlag.KeyDown);
Thread.Sleep(10);
WindowsMessageService.SendKey(key, KeyFlag.KeyUp);
Your first problem is that most games make use of DirectX input. You will have to make use of the following to send keys to the game. Also, you would need to send up and down key to simulate the keypress for the game.
[StructLayout(LayoutKind.Sequential)]
struct MouseInput
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct KeyboardInput
{
public short wVk; //Virtual KeyCode (not needed here)
public short wScan; //Directx Keycode
public int dwFlags; //This tells you what is use (Keyup, Keydown..)
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HardwareInput
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Explicit)]
struct Input
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)]
public MouseInput mi;
[FieldOffset(4)]
public KeyboardInput ki;
[FieldOffset(4)]
public HardwareInput hi;
}
[Flags]
public enum KeyFlag
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
UniCode = 0x0004,
ScanCode = 0x0008
}
public static class WindowsMessageService
{
[DllImport("user32.dll")]
private static extern UInt32 SendInput(UInt32 nInputs,[MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] Input[] pInputs, Int32 cbSize);
public static void SendInput(short keycode, KeyFlag keyFlag)
{
var inputData = new Input[1];
inputData[0].type = 1;
inputData[0].ki.wScan = keycode;
inputData[0].ki.dwFlags = (int)keyFlag;
inputData[0].ki.time = 0;
inputData[0].ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, inputData, Marshal.SizeOf(typeof(Input)));
}
public static void SendKey(short keyCode, KeyFlag keyFlag)
{
SendInput(keyCode, keyFlag | KeyFlag.ScanCode);
}
}
Example of usage:
short key = 0x3B; // F1 key
WindowsMessageService.SendKey(key, KeyFlag.KeyDown);
Thread.Sleep(10);
WindowsMessageService.SendKey(key, KeyFlag.KeyUp);

Registering a touch screen HID with RegisterRawInputDevices does not work

I am trying to get raw input data from a Surface touch screen, using RAWINPUT API.
Getting the devices list works good. But when I want to register the touch screen device with RegisterRawInputDevices, I have issues : the function returns false with 87 (ERROR_INVALID_PARAMETER) in GetLastError... I have tried different things that I read online but none work.
I am using Interop on C# for very simple desktop console application, developping with Visual Studio 2013 on Windows 8.1. The target is a Surface Pro 3.
The code doing the work with the API is hereunder... (sorry for the ugly editing).
I will be so thanksful for your help :)
Pierre
CLASS for the API wrapping in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ConsoleApplication3
{
class APIWrapper
{
#region Properties
private static int _vendorID=-1;
public static int VendorID
{
get { return _vendorID; }
}
private static int _productID=-1;
public static int ProductID
{
get { return _productID; }
}
#endregion
#region API structs
internal struct RAWINPUTDEVICELIST_ELMT
{
public IntPtr hDevice;
public uint dwType;
}
public enum RawInputDeviceType : uint
{
RIM_TYPEMOUSE = 0,
RIM_TYPEKEYBOARD = 1,
RIM_TYPEHID = 2,
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWINPUTDEVICE
{
public ushort usUsagePage;
public ushort usUsage;
public int dwFlags;
public IntPtr hwndTarget;
}
public enum RawInputDeviceInfoType : uint
{
RIDI_DEVICENAME = 0x20000007,
RIDI_DEVICEINFO = 0x2000000b,
RIDI_PREPARSEDDATA = 0x20000005,
}
public const ushort RIDEV_INPUTSINK =0x00000100;
public const ushort RIDEV_PAGEONLY = 0x00000020;
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_HID
{
public int dwVendorId;
public int dwProductId;
public int dwVersionNumber;
public ushort usUsagePage;
public ushort usUsage;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_MOUSE
{
public int dwId;
public int dwNumberOfButtons;
public int dwSampleRate;
public bool fHasHorizontalWheel;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_KEYBOARD
{
public int dwType;
public int dwSubType;
public int dwKeyboardMode;
public int dwNumberOfFunctionKeys;
public int dwNumberOfIndicators;
public int dwNumberOfKeysTotal;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RID_DEVICE_INFO
{
[FieldOffset(0)]
public uint cbSize;
[FieldOffset(4)]
public RawInputDeviceType dwType;
[FieldOffset(8)]
public RID_DEVICE_INFO_MOUSE mouse;
[FieldOffset(8)]
public RID_DEVICE_INFO_KEYBOARD keyboard;
[FieldOffset(8)]
public RID_DEVICE_INFO_HID hid;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWINPUTHEADER
{
public RawInputDeviceType dwType;
public int dwSize;
public IntPtr hDevice;
public uint wParam;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RAWMOUSE
{
[FieldOffset(0)]
public ushort usFlags;
[FieldOffset(2)]
public uint ulButtons;
[FieldOffset(4)]
public ushort usButtonFlags;
[FieldOffset(2)]
public ushort usButtonData;
[FieldOffset(6)]
public uint ulRawButtons;
[FieldOffset(10)]
public int lLastX;
[FieldOffset(14)]
public int lLastY;
[FieldOffset(18)]
public uint ulExtraInformation;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWKEYBOARD
{
public ushort MakeCode;
public ushort Flags;
public ushort Reserved;
public ushort VKey;
public uint Message;
public uint ExtraInformation;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWHID
{
public int dwSizeHid;
public int dwCount;
//use of a pointer here for struct reason
public IntPtr pbRawData;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RAWINPUT
{
[FieldOffset(0)]
public RAWINPUTHEADER header;
[FieldOffset(16 + 8)]
public RAWMOUSE mouse;
[FieldOffset(16 + 8)]
public RAWKEYBOARD keyboard;
[FieldOffset(16 + 8)]
public RAWHID hid;
}
#endregion
#region API functions
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetRawInputDeviceList([In, Out] RAWINPUTDEVICELIST_ELMT[] InputdeviceList, [In, Out] ref uint puiNumDevices, [In] uint cbSize);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetRawInputDeviceInfo([In] IntPtr hDevice, [In] RawInputDeviceInfoType uiCommand, [In, Out] IntPtr pData, [In, Out] ref uint pcbSize);
[DllImport("user32.dll", SetLastError = true)]
static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevices, uint uiNumDevices, uint cbSize);
[DllImport("user32.dll")]
static extern uint GetRegisteredRawInputDevices([In, Out] RAWINPUTDEVICE[] InputdeviceList, [In, Out] ref uint puiNumDevices, [In] uint cbSize);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetRawInputBuffer([In,Out] RAWINPUT[] pData, [In, Out] ref uint pcbSize, [In] uint cbSizeHeader);
#endregion
#region Methods for devices
public static bool GetRawInputDeviceList()
{
bool res = false;
RAWINPUTDEVICELIST_ELMT[] pRawInputDeviceList = null;
uint puiNumDevices = 0;
uint returnCode = GetRawInputDeviceList(pRawInputDeviceList, ref puiNumDevices, (uint)Marshal.SizeOf(new RAWINPUTDEVICELIST_ELMT()));
res = (0xFFFFFFFF != returnCode);
if (res)
{
//alloc array
pRawInputDeviceList = new RAWINPUTDEVICELIST_ELMT[puiNumDevices];
//get devices
returnCode = GetRawInputDeviceList(pRawInputDeviceList, ref puiNumDevices, (uint)Marshal.SizeOf((typeof(RAWINPUTDEVICELIST_ELMT))));
res = (0xFFFFFFFF != returnCode);
if (res)
{
//look for the touchscreen.
bool foundTouchScreen = false;
foreach (RAWINPUTDEVICELIST_ELMT rawInputDevice in pRawInputDeviceList)
{
//IntPtr pData = IntPtr.Zero;
//uint strsize = 0;
//IntPtr deviceHandle = rawInputDevice.hDevice;
//returnCode = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.RIDI_DEVICENAME, pData, ref strsize);
//pData = Marshal.AllocHGlobal((int)strsize);
//returnCode = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.RIDI_DEVICENAME, pData, ref strsize);
////Console.WriteLine("Result = " + returnCode + " ErrorCode = " + Marshal.GetLastWin32Error());
//string name = Marshal.PtrToStringAnsi(pData);
//Console.WriteLine("Name = " + name);
uint structsize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
RID_DEVICE_INFO di = new RID_DEVICE_INFO();
di.cbSize = structsize;
IntPtr pData = Marshal.AllocHGlobal((int)structsize);
returnCode = GetRawInputDeviceInfo(rawInputDevice.hDevice, RawInputDeviceInfoType.RIDI_DEVICEINFO, pData, ref structsize);
if (0xFFFFFFF != returnCode && 0 != returnCode)
{
di = (RID_DEVICE_INFO)Marshal.PtrToStructure(pData, typeof(RID_DEVICE_INFO));
//Console.WriteLine("di.dwType = " + Enum.GetName(typeof(RawInputDeviceType), di.dwType));
switch (di.dwType)
{
case RawInputDeviceType.RIM_TYPEHID:
/* Console.WriteLine("di.hid.dwVendorId = " + di.hid.dwVendorId);
Console.WriteLine("di.hid.dwProductId = " + di.hid.dwProductId);
Console.WriteLine("di.hid.dwVersionNumber = " + di.hid.dwVersionNumber);
Console.WriteLine("di.hid.usUsagePage = " + di.hid.usUsagePage);
Console.WriteLine("di.hid.usUsage = " + di.hid.usUsage);*/
if (0x0D == di.hid.usUsagePage && 0x04 == di.hid.usUsage)
{
_vendorID = di.hid.dwVendorId;
_productID = di.hid.dwProductId;
foundTouchScreen = true;
}
break;
case RawInputDeviceType.RIM_TYPEKEYBOARD:
case RawInputDeviceType.RIM_TYPEMOUSE:
default:
break;
}
if (foundTouchScreen)
{
RAWINPUTDEVICE[] rawInputDevicesToMonitor = new RAWINPUTDEVICE[1];
RAWINPUTDEVICE device = new RAWINPUTDEVICE();
device.dwFlags =RIDEV_INPUTSINK;
device.hwndTarget = Process.GetCurrentProcess().MainWindowHandle;
device.usUsage = di.hid.usUsage;
device.usUsagePage = di.hid.usUsagePage;
rawInputDevicesToMonitor[0] = device;
if (!RegisterRawInputDevices(rawInputDevicesToMonitor, (uint)1, (uint)Marshal.SizeOf(new RAWINPUTDEVICE())))
{
Console.WriteLine("Registration of device --> NOK (error: " + Marshal.GetLastWin32Error()+")");
RAWINPUTDEVICE [] pRegisteredRawInputDeviceList = null;
uint puiNumRegDevices = 0;
returnCode = GetRegisteredRawInputDevices(pRegisteredRawInputDeviceList, ref puiNumRegDevices, (uint)Marshal.SizeOf(new RAWINPUTDEVICE()));
res = (0xFFFFFFFF != returnCode);
if (res)
{
//alloc array
pRegisteredRawInputDeviceList = new RAWINPUTDEVICE[puiNumRegDevices];
//get devices
returnCode = GetRegisteredRawInputDevices(pRegisteredRawInputDeviceList, ref puiNumRegDevices, (uint)Marshal.SizeOf((typeof(RAWINPUTDEVICE))));
Console.WriteLine("Registered devices nb : " + returnCode);
}
}
break;
}
}
}
}
/*Need to set RIDEV_INPUTSINK in the dwFlags member and set hwndTarget to be able to make use of this function otherwise
* GetRawInputBuffer will ALWAYS say 0 when you try to find out what size you need the buffer to be.
*/
}
/*else
int error = Marshal.GetLastWin32Error();*/
return res;
}
#endregion
}
}
MAIN CLASS:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
//look for the touch screen device
if (!APIWrapper.GetRawInputDeviceList())
{
Console.WriteLine("Error occured when getting RawInputDevice List.");
}
if (APIWrapper.VendorID == -1 && APIWrapper.ProductID == -1)
{
Console.WriteLine("No Touchscreen device has been found.");
}
else
{
Console.WriteLine("Touchscreen found : VendorID=" + APIWrapper.VendorID + " ProductID=" + APIWrapper.ProductID);
//wait for rawinputdata
Console.WriteLine("Waiting data loop : started.");
uint dataNb = APIWrapper.ReadHIDData();
switch (dataNb)
{
case 0xFFFFFFFF:
Console.WriteLine("An error occured.");
break;
case 0:
Console.WriteLine("No data received.");
break;
default:
Console.WriteLine(dataNb + " rawInputData received");
break;
}
Console.WriteLine("Waiting data loop : ended.");
}
Console.ReadLine();
}
}
}
Try to use mfakane/rawinput-sharp: C# wrapper library for Raw Input

C# SendInput Alt/Ctrl/Shift Keys not getting Released

I am using the below code to pass special keys using SendInput. I am facing one strange issue. If user sends any of Alt/Ctrl/Shift, the key remains pressed e.g. if user passes Alt + F4, the code runs properly and action is completed successfully but Alt key remains pressed. I need to manually click Alt key after the operation is completed. Please let me know to handle the same in the code itself. Below is the code used to send special keys.
namespace RemoteDesktopSendKeys
{
class Program
{
struct INPUT
{
public INPUTType type;
public INPUTUnion Event;
}
[StructLayout(LayoutKind.Explicit)]
struct INPUTUnion
{
[FieldOffset(0)]
internal MOUSEINPUT mi;
[FieldOffset(0)]
internal KEYBDINPUT ki;
[FieldOffset(0)]
internal HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public KEYEVENTF dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
enum INPUTType : uint
{
INPUT_KEYBOARD = 1
}
[Flags]
enum KEYEVENTF : uint
{
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
SCANCODE = 0x0008,
UNICODE = 0x0004
}
[DllImport("user32.dll", SetLastError = true)]
static extern UInt32 SendInput(int numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);
[DllImport("user32.dll")]
public static extern IntPtr GetMessageExtraInfo();
[System.Runtime.InteropServices.DllImport("user32.dll")]
internal static extern uint MapVirtualKey(uint uCode, uint uMapType);
private const int KEYEVENTF_KEYUP1 = 0x0002;
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern int MapVirtualKey(int uCode, int uMapType);
static void Main(string[] args)
{
Thread.Sleep(3000);
int[] keyboardStrokes = { (int)Keys.LMenu,(int)Keys.F4 };
//int[] keyboardStrokes = { (int)Keys.ControlKey, (int)Keys.A };
SendSpecialKeys("test", keyboardStrokes);
//SendSpecialKeys("F5",keyboardStrokes);
}
private static void SendSpecialKeys(string text, int[] modifiers)
{
List<int> arrKeys = new List<int>();
Keys key;
if (modifiers != null && modifiers.Length > 0)
{
for (int i = 0; i < modifiers.Length; i++)
{
arrKeys.Add(modifiers[i]);
}
}
if (!string.IsNullOrEmpty(text))
{
if (Enum.TryParse(text, out key))
arrKeys.Add((int)key);
else
SendText(text);
}
System.Threading.Thread.Sleep(1000);
int[] arrKeyStrokes = arrKeys.ToArray();
INPUT[] inputs = new INPUT[arrKeyStrokes.Length + 1];
for (int i = 0; i < arrKeyStrokes.Length; i++)
{
uint skey = MapVirtualKey((uint)arrKeyStrokes[i], (uint)0x0);
inputs[i].type = INPUTType.INPUT_KEYBOARD;
inputs[i].Event.ki.dwFlags = KEYEVENTF.SCANCODE;
inputs[i].Event.ki.wScan = (ushort)skey;
}
inputs[arrKeyStrokes.Length].type = INPUTType.INPUT_KEYBOARD;
inputs[arrKeyStrokes.Length].Event.ki.dwFlags = KEYEVENTF.SCANCODE;
inputs[arrKeyStrokes.Length].Event.ki.dwFlags |= KEYEVENTF.KEYUP;
SendInput(inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
public static void SendText(string text)
{
List<INPUT> kbInput = new List<INPUT>();
foreach (char c in text)
{
// Send a key down followed by key up.
foreach (bool keyUp in new bool[] { false, true })
{
INPUT input = new INPUT
{
type = INPUTType.INPUT_KEYBOARD,
Event = new INPUTUnion
{
// This will contain keyboard event information
ki = new KEYBDINPUT
{
wVk = 0,
wScan = c,
dwFlags = KEYEVENTF.UNICODE | (keyUp ? KEYEVENTF.KEYUP : 0),
dwExtraInfo = GetMessageExtraInfo(),
}
}
};
kbInput.Add(input);
}
}
// Call SendInputWindows API to send input
SendInput((int)kbInput.Count, kbInput.ToArray(), Marshal.SizeOf(typeof(INPUT)));
}
}
}
The following code can be used to release particular key. Below is the sample code to release control key.
uint ctrlkey = MapVirtualKey((uint)Keys.ControlKey, (uint)0x0);
inputs[index].type = INPUTType.INPUT_KEYBOARD;
inputs[index].Event.ki.dwFlags = KEYEVENTF.SCANCODE;
inputs[index].Event.ki.dwFlags |= KEYEVENTF.KEYUP;
inputs[index].Event.ki.wScan = (ushort)ctrlkey;
Need to make sure that proper key is released by passing index properly.

SetupDiEnumDeviceInterfaces() always returns false - C# WPF

I am trying to connect to a USB device that is detected as a CDC device on my system using the following code :
(I have presented only the part of the code relevant to my problem)
The code compiles fine and SetupDiGetClassDevs function runs ok too.
But SetupDiEnumDeviceInterfaces always returns false and because of this I am not able to move any further. Please tell me where it is wrong. Thanks.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO.Ports;
//**************************************************************
// Static class for access to USB dll for all the activity
// related to USB device
//**************************************************************
namespace USBDeviceConnect
{
#region Unmanaged
public class Native
{
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetupDiGetClassDevs(
ref Guid ClassGuid,
IntPtr Enumerator,
IntPtr hwndParent,
UInt32 Flags);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
public static extern bool SetupDiEnumDeviceInterfaces(
IntPtr hDevInfo,
SP_DEVINFO_DATA devInfo,
ref Guid interfaceClassGuid,
UInt32 memberIndex,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
[DllImport(#"setupapi.dll", CharSet = CharSet.Auto)]
public static extern Boolean SetupDiEnumDeviceInterfaces(
IntPtr hDevInfo,
IntPtr devInfo,
ref Guid interfaceClassGuid,
UInt32 memberIndex,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
public static extern int SetupDiDestroyDeviceInfoList(
IntPtr DeviceInfoSet);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
public static extern bool SetupDiEnumDeviceInfo(
IntPtr DeviceInfoSet,
UInt32 MemberIndex,
ref SP_DEVINFO_DATA DeviceInfoData);
//SP_DEVINFO_DATA
[StructLayout(LayoutKind.Sequential)]
public struct SP_DEVINFO_DATA
{
public int cbSize;
public Guid ClassGuid;
public int DevInst;
public ulong Reserved;
}
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVICE_INTERFACE_DATA
{
public int cbSize;
public Guid interfaceClassGuid;
public int flags;
public ulong reserved;
};
//PARMS
public const int DIGCF_ALLCLASSES = (0x00000004);
public const int DIGCF_PRESENT = (0x00000002);
public const int DIGCF_PROFILE = (0x00000008);
public const int DIGCF_DEVICEINTERFACE = (0x00000010);
public const int INVALID_HANDLE_VALUE = -1;
public const int MAX_DEV_LEN = 1000;
public const int DEVICE_NOTIFY_WINDOW_HANDLE = (0x00000000);
public const int DEVICE_NOTIFY_SERVICE_HANDLE = (0x00000001);
public const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = (0x00000004);
public const int DBT_DEVTYP_DEVICEINTERFACE = (0x00000005);
public const int DBT_DEVNODES_CHANGED = (0x0007);
public const int WM_DEVICECHANGE = (0x0219);
public const int DIF_PROPERTYCHANGE = (0x00000012);
public const int DICS_FLAG_GLOBAL = (0x00000001);
public const int DICS_FLAG_CONFIGSPECIFIC = (0x00000002);
public const int DICS_ENABLE = (0x00000001);
public const int DICS_DISABLE = (0x00000002);
public const long ERROR_NO_MORE_ITEMS = 259L;
public const int ERROR_SUCCESS = 0;
}
#endregion
/****************************************************************************/
static class AccessUSB
{
public static void Main()
{
ConnectToDevice();
}
/* Execution starts here */
public static void ConnectToDevice()
{
/* Get the info of all connected devices */
//Globally Unique Identifier (GUID) for CDC class devices.
Guid InterfaceClassGuid = new Guid("a5dcbf10653011d2901f00c04fb951ed");
IntPtr DeviceInfoTable = (IntPtr)Native.INVALID_HANDLE_VALUE;
Native.SP_DEVICE_INTERFACE_DATA InterfaceDataStructure = new Native.SP_DEVICE_INTERFACE_DATA();
Native.SP_DEVINFO_DATA DevInfoData = new Native.SP_DEVINFO_DATA();
uint InterfaceIndex = 0;
uint ErrorStatus;
StringBuilder DeviceName = new StringBuilder();
DeviceInfoTable = Native.SetupDiGetClassDevs(ref InterfaceClassGuid, IntPtr.Zero, IntPtr.Zero, Native.DIGCF_PRESENT | Native.DIGCF_DEVICEINTERFACE);
if (DeviceInfoTable.ToInt32() != Native.INVALID_HANDLE_VALUE)
{
//Initialize an appropriate SP_DEVINFO_DATA structure.
DevInfoData.cbSize = Marshal.SizeOf(DevInfoData);
while (true)
{
InterfaceDataStructure.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(InterfaceDataStructure);
bool bRslt = Native.SetupDiEnumDeviceInterfaces(DeviceInfoTable, IntPtr.Zero, ref InterfaceClassGuid, InterfaceIndex, ref InterfaceDataStructure);
if (bRslt == true)
{
ErrorStatus = (uint)System.Runtime.InteropServices.Marshal.GetLastWin32Error();
if (Native.ERROR_NO_MORE_ITEMS == ErrorStatus)
{
Native.SetupDiDestroyDeviceInfoList(DeviceInfoTable);//Clean up the old structure we no longer need.
return;
}
}
else //Else some other kind of unknown error ocurred...
{
ErrorStatus = (uint)System.Runtime.InteropServices.Marshal.GetLastWin32Error();
Native.SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
return;
}
InterfaceIndex++;
}//end of while(true)
}
}
}
}
I'm not sure why you are trying to use SetupAPI. If it is a detected as a CDC ACM device, then it should have the usbser.sys driver associated with it, and it should show a COM port number in the Device Manager, and you can connect to that COM port using the .NET SerialPort class:
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.aspx

Categories