sl@25: using System; sl@25: using System.Windows.Forms; sl@25: using System.Runtime.InteropServices; sl@25: using System.Diagnostics; sl@25: using System.Text; sl@25: using Microsoft.Win32.SafeHandles; StephaneLenclud@53: using Win32; sl@25: sl@25: namespace Hid sl@25: { sl@25: /// sl@25: /// Represent a HID device. sl@25: /// StephaneLenclud@52: public class HidDevice: IDisposable sl@25: { sl@25: public string Name { get; private set; } sl@25: public string Manufacturer { get; private set; } sl@25: public string Product { get; private set; } sl@25: public ushort VendorId { get; private set; } sl@25: public ushort ProductId { get; private set; } sl@25: public ushort Version { get; private set; } StephaneLenclud@52: public IntPtr PreParsedData {get; private set;} StephaneLenclud@53: public RID_DEVICE_INFO Info { get {return iInfo;} } StephaneLenclud@53: private RID_DEVICE_INFO iInfo; sl@25: sl@25: /// sl@26: /// Class constructor will fetch this object properties from HID sub system. sl@25: /// sl@26: /// Device Handle as provided by RAWINPUTHEADER.hDevice, typically accessed as rawinput.header.hDevice sl@25: public HidDevice(IntPtr hRawInputDevice) sl@25: { StephaneLenclud@52: PreParsedData = IntPtr.Zero; sl@25: //Fetch various information defining the given HID device StephaneLenclud@52: Name = Win32.Utils.RawInput.GetDeviceName(hRawInputDevice); StephaneLenclud@52: StephaneLenclud@52: //Get our HID descriptor pre-parsed data StephaneLenclud@52: PreParsedData = Win32.Utils.RawInput.GetPreParsedData(hRawInputDevice); StephaneLenclud@53: if (PreParsedData == IntPtr.Zero) StephaneLenclud@53: { StephaneLenclud@53: throw new Exception("HidDevice: GetPreParsedData failed!"); StephaneLenclud@53: } StephaneLenclud@53: StephaneLenclud@53: //Fetch device info StephaneLenclud@53: iInfo = new RID_DEVICE_INFO(); StephaneLenclud@53: if (!Win32.Utils.RawInput.GetDeviceInfo(hRawInputDevice, ref iInfo)) StephaneLenclud@53: { StephaneLenclud@53: throw new Exception("HidDevice: GetDeviceInfo failed!"); StephaneLenclud@53: } sl@25: sl@25: //Open our device from the device name/path sl@25: SafeFileHandle handle=Win32.Function.CreateFile(Name, sl@25: Win32.FileAccess.NONE, sl@25: Win32.FileShare.FILE_SHARE_READ|Win32.FileShare.FILE_SHARE_WRITE, sl@25: IntPtr.Zero, sl@25: Win32.CreationDisposition.OPEN_EXISTING, sl@25: Win32.FileFlagsAttributes.FILE_FLAG_OVERLAPPED, sl@25: IntPtr.Zero sl@25: ); sl@25: StephaneLenclud@53: //TODO: should we throw instead? sl@25: if (handle.IsInvalid) sl@25: { sl@25: Debug.WriteLine("Failed to CreateFile from device name " + Marshal.GetLastWin32Error().ToString()); sl@25: } sl@25: else sl@25: { sl@25: //Get manufacturer string sl@25: StringBuilder manufacturerString = new StringBuilder(256); sl@25: if (Win32.Function.HidD_GetManufacturerString(handle, manufacturerString, manufacturerString.Capacity)) sl@25: { sl@25: Manufacturer = manufacturerString.ToString(); sl@25: } sl@25: sl@25: //Get product string sl@25: StringBuilder productString = new StringBuilder(256); sl@25: if (Win32.Function.HidD_GetProductString(handle, productString, productString.Capacity)) sl@25: { sl@25: Product = productString.ToString(); sl@25: } sl@25: sl@25: //Get attributes sl@25: Win32.HIDD_ATTRIBUTES attributes=new Win32.HIDD_ATTRIBUTES(); sl@25: if (Win32.Function.HidD_GetAttributes(handle, ref attributes)) sl@25: { sl@25: VendorId = attributes.VendorID; sl@25: ProductId = attributes.ProductID; sl@25: Version = attributes.VersionNumber; sl@25: } sl@25: sl@25: handle.Close(); sl@25: } sl@25: } sl@25: StephaneLenclud@52: StephaneLenclud@52: /// StephaneLenclud@52: /// Make sure dispose is called even if the user forgot about it. StephaneLenclud@52: /// StephaneLenclud@52: ~HidDevice() StephaneLenclud@52: { StephaneLenclud@52: Dispose(); StephaneLenclud@52: } StephaneLenclud@52: StephaneLenclud@52: /// StephaneLenclud@52: /// Dispose is just for unmanaged clean-up. StephaneLenclud@52: /// Make sure calling disposed multiple times does not crash. StephaneLenclud@52: /// See: http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface/538238#538238 StephaneLenclud@52: /// StephaneLenclud@52: public void Dispose() StephaneLenclud@52: { StephaneLenclud@52: Marshal.FreeHGlobal(PreParsedData); StephaneLenclud@52: PreParsedData = IntPtr.Zero; StephaneLenclud@52: } StephaneLenclud@52: sl@25: /// sl@25: /// Print information about this device to our debug output. sl@25: /// sl@25: public void DebugWrite() sl@25: { sl@25: Debug.WriteLine("================ HID ========================================================================================="); sl@25: Debug.WriteLine("==== Name: " + Name); sl@25: Debug.WriteLine("==== Manufacturer: " + Manufacturer); sl@25: Debug.WriteLine("==== Product: " + Product); sl@25: Debug.WriteLine("==== VendorID: 0x" + VendorId.ToString("X4")); sl@25: Debug.WriteLine("==== ProductID: 0x" + ProductId.ToString("X4")); sl@25: Debug.WriteLine("==== Version: " + Version.ToString()); sl@25: Debug.WriteLine("=============================================================================================================="); sl@25: } sl@25: sl@25: } sl@25: sl@25: }