PORTS Forum
Ports and Interfaces => USB => Topic started by: jain1.anuj on January 03, 2012, 04:18:50 am
-
hello,
i am working on a USB HID device. it's a proximity device which detects the person's distance and fire keystrokes accordingly. i want the handle for the device so that i can perform the read and write operations over it.
i am using Hid.dll , Setupapi.dll , kernel32.dll. when i am using the CreateFile function, it is reaturning the invalid handle. can anybody help me in this regard.
the code is written below:-
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
public Form1() : base()
{
InitializeComponent();
}
[ StructLayout( LayoutKind.Sequential ) ]
internal class DEV_BROADCAST_HDR
{
internal Int32 dbch_size;
internal Int32 dbch_devicetype;
internal Int32 dbch_reserved;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal class DEV_BROADCAST_DEVICEINTERFACE_1
{
internal Int32 dbcc_size;
internal Int32 dbcc_devicetype;
internal Int32 dbcc_reserved;
[MarshalAs(UnmanagedType.ByValArray,
ArraySubType = UnmanagedType.U1,
SizeConst = 16)]
internal Byte[] dbcc_classguid;
[MarshalAs(UnmanagedType.ByValArray,
SizeConst = 255)]
internal Char[] dbcc_name;
}
[DllImport("hid.dll", SetLastError = true)]
public static extern void HidD_GetHidGuid(ref System.Guid HidGuid);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern IntPtr SetupDiGetClassDevs
(ref System.Guid ClassGuid,
IntPtr Enumerator,
IntPtr hwndParent,
Int32 Flags);
public struct SP_DEVINFO_DATA
{
public int cbSize;
public System.Guid ClassGuid;
public int DevInst;
public int Reserved;
}
internal struct SP_DEVICE_INTERFACE_DATA
{
internal Int32 cbSize;
internal Guid InterfaceClassGuid;
internal Int32 Flags;
internal IntPtr Reserved;
}
[DllImport("setupapi.dll", SetLastError = true)]
internal static extern Boolean SetupDiEnumDeviceInterfaces
(IntPtr DeviceInfoSet,
IntPtr DeviceInfoData,
ref System.Guid InterfaceClassGuid,
Int32 MemberIndex,
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal Int32 cbSize;
internal String DevicePath;
}
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern Boolean SetupDiGetDeviceInterfaceDetail
(IntPtr DeviceInfoSet,
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
IntPtr DeviceInterfaceDetailData,
Int32 DeviceInterfaceDetailDataSize,
ref Int32 RequiredSize,
IntPtr DeviceInfoData);
[DllImport("setupapi.dll", SetLastError = true)]
internal static extern Int32 SetupDiDestroyDeviceInfoList
(IntPtr DeviceInfoSet);
[DllImport("setupapi.dll", SetLastError = true)]
internal static extern Boolean SetupDiEnumDeviceInfo(
IntPtr DeviceInfoSet,
Int32 MemberIndex,
SP_DEVINFO_DATA DeviceInfoData);
internal const Int32 DBT_DEVTYP_HANDLE = 6;
internal const Int32 DBT_DEVTYP_DEVICEINTERFACE = 5;
internal const Int32 DEVICE_NOTIFY_WINDOW_HANDLE = 0;
internal const Int32 DIGCF_PRESENT = 2;
internal const Int32 DIGCF_DEVICEINTERFACE = 0X10;
internal const Int32 WM_DEVICECHANGE = 0X219;
[StructLayout(LayoutKind.Sequential)]
internal class DEV_BROADCAST_DEVICEINTERFACE
{
internal Int32 dbcc_size;
internal Int32 dbcc_devicetype;
internal Int32 dbcc_reserved;
internal Guid dbcc_classguid;
internal Int16 dbcc_name;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr RegisterDeviceNotification
(IntPtr hRecipient,
IntPtr NotificationFilter,
Int32 Flags);
internal const Int32 DBT_DEVICEARRIVAL = 0X8000;
internal const Int32 DBT_DEVICEREMOVECOMPLETE = 0X8004;
public static Guid
GUID_DEVINTERFACE_USB_DEVICE = new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED");
internal const Int32 FILE_ATTRIBUTE_NORMAL = 0X80;
internal const Int32 FILE_FLAG_OVERLAPPED = 0x40000000;
internal const Int32 FILE_SHARE_READ = 1;
internal const Int32 FILE_SHARE_WRITE = 2;
internal const UInt32 GENERIC_READ = 0X80000000;
internal const UInt32 GENERIC_WRITE = 0X40000000;
internal const Int32 OPEN_EXISTING = 3;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern SafeFileHandle CreateFile
(String lpFileName,
UInt32 dwDesiredAccess,
Int32 dwShareMode,
IntPtr lpSecurityAttributes,
Int32 dwCreationDisposition,
Int32 dwFlagsAndAttributes,
Int32 hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern int GetLastError();
[StructLayout(LayoutKind.Sequential)]
internal struct HIDD_ATTRIBUTES
{
internal Int32 Size;
internal UInt16 VendorID;
internal UInt16 ProductID;
internal UInt16 VersionNumber;
}
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_GetAttributes
(SafeFileHandle HidDeviceObject, ref HIDD_ATTRIBUTES Attributes);
internal SafeFileHandle deviceHandle;
private Boolean Find(Message m)
{
Boolean deviceFound ;
Int32 bufferSize = 0;
IntPtr detailDataBuffer;
String[] devicePathName = new String[128];
Int32 memberIndex = 0;
ntPtr deviceInfoSet ;
deviceInfoSet = SetupDiGetClassDevs
(ref GUID_DEVINTERFACE_USB_DEVICE,
IntPtr.Zero,
IntPtr.Zero,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
//MessageBox.Show(deviceInfoSet.ToString());
deviceFound = false;
// Int32 memberIndex = 0;
SP_DEVICE_INTERFACE_DATA MyDeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
Boolean success = false;
MyDeviceInterfaceData.cbSize = Marshal.SizeOf( MyDeviceInterfaceData );
//do
//{
success = SetupDiEnumDeviceInterfaces
(deviceInfoSet,
IntPtr.Zero,
ref GUID_DEVINTERFACE_USB_DEVICE,
memberIndex,
ref MyDeviceInterfaceData);
//MessageBox.Show(success.ToString());
if (!success)
{
return false;
}
else
{
success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
ref MyDeviceInterfaceData,
IntPtr.Zero,
0,
ref bufferSize,
IntPtr.Zero);
detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
Marshal.WriteInt32
(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
ref MyDeviceInterfaceData,
detailDataBuffer,
bufferSize,
ref bufferSize,
IntPtr.Zero);
//String devicePathName = "";
IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt32() + 4);
devicePathName[memberIndex] = Marshal.PtrToStringAuto(pDevicePathName);
MessageBox.Show("path of device " + devicePathName[memberIndex]);
DEV_BROADCAST_DEVICEINTERFACE_1 devBroadcastDeviceInterface =
new DEV_BROADCAST_DEVICEINTERFACE_1();
DEV_BROADCAST_HDR devBroadcastHeader = new DEV_BROADCAST_HDR();
Marshal.PtrToStructure(m.LParam, devBroadcastHeader);
if ((devBroadcastHeader.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE))
{
Int32 stringSize = Convert.ToInt32((devBroadcastHeader.dbch_size - 32) / 2);
Array.Resize(ref devBroadcastDeviceInterface.dbcc_name, stringSize);
Marshal.PtrToStructure(m.LParam, devBroadcastDeviceInterface);
String deviceNameString = new String(devBroadcastDeviceInterface.dbcc_name, 0, stringSize);
MessageBox.Show("extracted path-: " + deviceNameString.ToString());
if ((String.Compare(deviceNameString, devicePathName[0], true) == 0))
{
MessageBox.Show("device name matched");
}
else
{
MessageBox.Show("device name not matched");
}
}
deviceFound = true ;
}
if (deviceFound)
{
// memberIndex = 0;
MessageBox.Show(devicePathName[0]);
//SafeFileHandle deviceHandle;
MessageBox.Show("inside file handle");
deviceHandle = CreateFile
("##?#USB#Vid_18c8&Pid_2bfa#063#{A5DCBF10-6530-11D2-901F-00C04FB951ED}",/*devicePathName[0]/*, /*GENERIC_WRITE | GENERIC_READ*/0, FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero, OPEN_EXISTING, 0/*FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED*/, 0);
MessageBox.Show("file handle " + deviceHandle.ToString());
MessageBox.Show("handle value : " + deviceHandle.DangerousGetHandle().ToString());
if (!deviceHandle.IsInvalid)
{
MessageBox.Show("valid");
HIDD_ATTRIBUTES attribs = new HIDD_ATTRIBUTES();
attribs.Size = Marshal.SizeOf(attribs);
HidD_GetAttributes(deviceHandle, ref attribs);
MessageBox.Show("vendor id " + Convert.ToString(attribs.VendorID, 16));
}
else
{
int error = GetLastError();
MessageBox.Show("in else " + error.ToString());
}
}
return deviceFound;
}
private void Register()
{
DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface =
new DEV_BROADCAST_DEVICEINTERFACE();
IntPtr devBroadcastDeviceInterfaceBuffer;
IntPtr deviceNotificationHandle = IntPtr.Zero;
Int32 size = 0;
// frmMy is the form that will receive device-change messages.
size = Marshal.SizeOf( devBroadcastDeviceInterface );
devBroadcastDeviceInterface.dbcc_size = size;
devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
devBroadcastDeviceInterface.dbcc_reserved = 0;
devBroadcastDeviceInterface.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal( size );
Marshal.StructureToPtr
( devBroadcastDeviceInterface,
devBroadcastDeviceInterfaceBuffer,
true );
deviceNotificationHandle = RegisterDeviceNotification
(new Form1().Handle,
devBroadcastDeviceInterfaceBuffer,
DEVICE_NOTIFY_WINDOW_HANDLE);
}
private void Form1_Load(object sender, EventArgs e)
{
Register();
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_DEVICECHANGE)
{
OnDeviceChange(m);
}
base.WndProc(ref m);
}
private void OnDeviceChange(Message m)
{
if ((m.WParam.ToInt32() == DBT_DEVICEARRIVAL))
{
MessageBox.Show("device arrived");
//Find(m);
if (Find(m))
{
MessageBox.Show("my device arrived");
}
}
else if ((m.WParam.ToInt32() == DBT_DEVICEREMOVECOMPLETE))
{
MessageBox.Show("device removed");
}
}
}
}
please help me in this regard. it is urgent
-
If your HID enumerates as a system keyboard, use Raw Input instead of the HID API.
Jan
-
thanks for the reply JAN.
let me explain you about the device. it's a proximity device. User configures the keystrokes from the application provided with the device. As soon as user gets away from the range of the device, the device fires the keystrokes that were configured and saved by the user in the device. The device don't have any keys in it. It just fires the keystrokes configured and saved in it. The device has just the sensor in it.
-
can anyone help me in solving my problem??
-
If the device's descriptors cause the host computer to see the device as a system keyboard, you need to use Raw Input or other means to read the keypresses, not the HID API. Whether it's a conventional keyboard doesn't matter. For example, many barcode scanners enumerate as system keyboards.
See if it shows up as a keyboard in Windows Device Manager.
Jan
-
This is how my device enumerates in the device manager. (see the attached image)
It is when i VIEW the device "By CONNECTION" in device manager.
[attachment deleted by admin]
-
View "by type" and see if it shows up as a keyboard.
Jan
-
It show like this if i view it "By Type". (attached file)
[attachment deleted by admin]
-
Click the "+" at Keyboards.
Jan
-
here it is
[attachment deleted by admin]
-
If the keyboard device disappears when you detach your device, it's a keyboard.
Jan
-
yes. it gets disappear when i de-attached the device.
so what should i use to read/write and registering the device? HID API's or RAW INPUT?
-
Raw input.
Jan
-
ok. but i dont think that we can write data with RAW INPUT. can we?
-
Just input. If you want to read and write, make it a generic HID and use the HID API. See my firmware for example descriptors:
http://www.lvr.com/hidpage.htm#MyExampleCode
Jan
-
ok. i took the help from your application and managed to get the handle to the device. but i am unable to read/write on my device. it is giving me message saying "Attempted to read or write protected memory. This is often an indication that other memory is corrupt".
i am using the
GUID_GUID_DEVINTERFACE_KEYBOARD = new Guid("884b96c3-56ef-11d1-bc8c-00a0c91405dd");
Moreover, i am unable to get the capabilities and attributes too. the code after retrieving the handle to the device is as follows. :-
deviceHandle = CreateFile(devicePathName[0], GENERIC_WRITE /*| GENERIC_READ*/ , FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero,
OPEN_EXISTING, 0, IntPtr.Zero);
int error = GetLastError();
MessageBox.Show("create file error code: " + error.ToString());
MessageBox.Show("create file handle value : " + deviceHandle.DangerousGetHandle().ToString());
if (!deviceHandle.IsInvalid)
{
MessageBox.Show("valid handle");
HIDD_ATTRIBUTES attribs = new HIDD_ATTRIBUTES();
attribs.Size = Marshal.SizeOf(attribs);
MessageBox.Show("attributes size: " + attribs.Size.ToString());
HidD_GetAttributes(deviceHandle, ref attribs);
MessageBox.Show("vendor id " + Convert.ToString(attribs.VendorID, 16));
}
else
{
//int error = GetLastError();
MessageBox.Show("in else ");
}
Capabilities = GetDeviceCapabilities(deviceHandle);
MessageBox.Show("capabilities: " + Capabilities.ToString());
hidUsage = GetHidUsage(Capabilities);
MessageBox.Show("usage : " + hidUsage);
Int32 numberOfInputBuffers = 0;
Boolean result;
if (!((IsWindows98Gold())))
{
result = HidD_GetNumInputBuffers(deviceHandle, ref numberOfInputBuffers);
MessageBox.Show("number of input buffer: " + numberOfInputBuffers.ToString());
}
else
{
// Under Windows 98 Gold, the number of buffers is fixed at 2.
numberOfInputBuffers = 2;
success = true;
}
readHandle = CreateFile(devicePathName[0], 0, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero);
MessageBox.Show("read handle : " + readHandle.DangerousGetHandle().ToString());
if (readHandle.IsInvalid)
{
exclusiveAccess = true;
}
else
{
writeHandle = CreateFile(devicePathName[0], GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
MessageBox.Show("write handle : " + writeHandle.DangerousGetHandle().ToString());
}
String byteValue = null;
Int32 count = 0;
Byte[] outFeatureReportBuffer = null;
MessageBox.Show("byte length : " + Capabilities.FeatureReportByteLength.ToString());
if ( ( Capabilities.FeatureReportByteLength > 0 ) )
{
outFeatureReportBuffer = new Byte[ Capabilities.FeatureReportByteLength ];
outFeatureReportBuffer[ 0 ] = 0;
outFeatureReportBuffer[ 1 ] = Convert.ToByte( 29 );
if ( Microsoft.VisualBasic.Information.UBound( outFeatureReportBuffer, 1 ) > 1 )
{
outFeatureReportBuffer[ 2 ] = Convert.ToByte( 80);
}
success = Write( outFeatureReportBuffer, deviceHandle );
if (success)
{
MessageBox.Show("A Feature report has been written.");
MessageBox.Show(" Feature Report ID: " + String.Format("{0:X2} ", outFeatureReportBuffer[0]));
MessageBox.Show(" Feature Report Data:");
for (count = 0; count <= outFeatureReportBuffer.Length - 1; count++)
{
byteValue = String.Format("{0:X2} ", outFeatureReportBuffer[count]);
MessageBox.Show(" " + byteValue);
}
}
else
{
MessageBox.Show("The attempt to write a Feature report failed.");
}
}
}
return deviceFound;
}
internal String GetHidUsage(HIDP_CAPS MyCapabilities)
{
Int32 usage = 0;
String usageDescription = "";
try
{
MessageBox.Show("page : " + Capabilities.UsagePage.ToString());
usage = MyCapabilities.UsagePage * 256 + MyCapabilities.Usage;
MessageBox.Show("usage in method : " + usage.ToString());
if (usage == Convert.ToInt32(0X102))
{
usageDescription = "mouse";
}
if (usage == Convert.ToInt32(0X106))
{
usageDescription = "keyboard";
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
MessageBox.Show("description : " + usageDescription);
return usageDescription;
}
internal Boolean Write( Byte[] outFeatureReportBuffer, SafeFileHandle hidHandle )
{
Boolean success = false;
try
{
success = HidD_SetFeature(hidHandle, outFeatureReportBuffer, outFeatureReportBuffer.Length);
MessageBox.Show( "HidD_SetFeature success = " + success );
}
catch ( Exception ex )
{
MessageBox.Show(ex.Message.ToString());
}
return success;
}
internal HIDP_CAPS GetDeviceCapabilities(SafeFileHandle hidHandle)
{
IntPtr preparsedData = new System.IntPtr();
Int32 result = 0;
Boolean success = false;
try
{
success = HidD_GetPreparsedData(hidHandle, ref preparsedData);
result = HidP_GetCaps(preparsedData, ref Capabilities);
if ((result != 0))
{
MessageBox.Show("");
MessageBox.Show(" Usage: " + Convert.ToString(Capabilities.Usage, 16));
MessageBox.Show(" Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
MessageBox.Show(" Input Report Byte Length: " + Capabilities.InputReportByteLength);
MessageBox.Show(" Output Report Byte Length: " + Capabilities.OutputReportByteLength);
MessageBox.Show(" Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
MessageBox.Show(" Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
MessageBox.Show(" Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
MessageBox.Show(" Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
MessageBox.Show(" Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
MessageBox.Show(" Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
MessageBox.Show(" Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
MessageBox.Show(" Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
MessageBox.Show(" Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
MessageBox.Show(" Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
MessageBox.Show(" Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);
Int32 vcSize = Capabilities.NumberInputValueCaps;
Byte[] valueCaps = new Byte[vcSize];
result = HidP_GetValueCaps(HidP_Input, valueCaps, ref vcSize, preparsedData);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
finally
{
if (preparsedData != IntPtr.Zero)
{
success = HidD_FreePreparsedData(preparsedData);
}
}
return Capabilities;
}
internal Boolean IsWindows98Gold()
{
Boolean result = false;
OperatingSystem myEnvironment = Environment.OSVersion;
// Windows 98 Gold is version 4.10 with a build number less than 2183.
System.Version version98SE = new System.Version( 4, 10, 2183 );
if (myEnvironment.Version < version98SE)
{
MessageBox.Show( "The OS is Windows 98 Gold." );
result = true;
}
else
{
MessageBox.Show( "The OS is more recent than Windows 98 Gold." );
result = false;
}
return result;
}
-
Did you modify the descriptors to make the device a generic HID?
Don't use the keyboard GUID. See my example code.
Jan
-
i did change the DESCRIPTOR to GUID_DEVINTERFACE_USB but the device does not get detected.
GUID_DEVINTERFACE_USB = new Guid("4D1E55B2-F16F-11CF-88CB-001111000030");
I even tried it with GUID_DEVINTERFACE_HID. it gives me ERROR 31:- "A device attached to the system is not functioning." when it it executes CreateFile() method.
GUID_DEVINTERFACE_HID = new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED");
-
Let me explain you about my device once again so that you must have a better understanding about it.
My device is an ultra-sonic proximity detector functioning as a USB keyboard. The primary purpose is for detecting users stepping away from a computer terminal they have un-locked (log-in active), and issuing keystrokes to lock or log-off the session on the computer. Now when you walk away from your system, you will benefit from a hands-free means of locking your computer.
I need both read/write operation on my device.
-
For read/write access other than keypresses and keyboard LEDs, make the device a generic HID, not a system keyboard. Define a report that indicates that the person has walked away. Write an application that logs off on receiving that report. I don't think you need keypresses to do that. Here is one example:
http://forums.techarena.in/software-development/1104154.htm
Use Output or Feature reports to send data of any kind to the device.
Jan
-
Can you please elaborate your above post a little bit more ?
-
My generic HID example code is here:
http://www.lvr.com/hidpage.htm#MyExampleCode
Jan