HidDevice.cs
author StephaneLenclud
Sun, 15 Feb 2015 13:30:54 +0100
changeset 59 89dfad9633b2
parent 56 cace0afae0fa
child 60 687cace560d2
permissions -rw-r--r--
Win32Hid: Fixing boolean bug and improving value caps union.
     1 using System;
     2 using System.Windows.Forms;
     3 using System.Runtime.InteropServices;
     4 using System.Diagnostics;
     5 using System.Text;
     6 using Microsoft.Win32.SafeHandles;
     7 using Win32;
     8 
     9 namespace Hid
    10 {
    11     /// <summary>
    12     /// Represent a HID device.
    13     /// </summary>
    14     public class HidDevice: IDisposable
    15     {
    16         public string Name { get; private set; }
    17         public string Manufacturer { get; private set; }
    18         public string Product { get; private set; }
    19         public ushort VendorId { get; private set; }
    20         public ushort ProductId { get; private set; }
    21         public ushort Version { get; private set; }
    22         //Pre-parsed HID descriptor
    23         public IntPtr PreParsedData {get; private set;}
    24         //Info
    25         public RID_DEVICE_INFO Info { get {return iInfo;} }
    26         private RID_DEVICE_INFO iInfo;
    27         //Capabilities
    28         public HIDP_CAPS Capabilities { get { return iCapabilities; } }
    29         private HIDP_CAPS iCapabilities;
    30         //Input Button Capabilities
    31         public HIDP_BUTTON_CAPS[] InputButtonCapabilities { get { return iInputButtonCapabilities; } }
    32         private HIDP_BUTTON_CAPS[] iInputButtonCapabilities;
    33         //Input Value Capabilities
    34         public HIDP_VALUE_CAPS[] InputValueCapabilities { get { return iInputValueCapabilities; } }
    35         private HIDP_VALUE_CAPS[] iInputValueCapabilities;
    36 
    37         
    38         
    39 
    40         /// <summary>
    41         /// Class constructor will fetch this object properties from HID sub system.
    42         /// </summary>
    43         /// <param name="hRawInputDevice">Device Handle as provided by RAWINPUTHEADER.hDevice, typically accessed as rawinput.header.hDevice</param>
    44         public HidDevice(IntPtr hRawInputDevice)
    45         {
    46             //Try construct and rollback if needed
    47             try
    48             {
    49                 Construct(hRawInputDevice);
    50             }
    51             catch (System.Exception ex)
    52             {
    53                 //Just rollback and propagate
    54                 Dispose();
    55                 throw ex;
    56             }
    57         }
    58 
    59 
    60         /// <summary>
    61         /// Make sure dispose is called even if the user forgot about it.
    62         /// </summary>
    63         ~HidDevice()
    64         {
    65             Dispose();
    66         }
    67 
    68         /// <summary>
    69         /// Private constructor.
    70         /// </summary>
    71         /// <param name="hRawInputDevice"></param>
    72         private void Construct(IntPtr hRawInputDevice)
    73         {
    74             PreParsedData = IntPtr.Zero;
    75             iInputButtonCapabilities = null;
    76             iInputValueCapabilities = null;
    77 
    78             //Fetch various information defining the given HID device
    79             Name = Win32.Utils.RawInput.GetDeviceName(hRawInputDevice);
    80 
    81             //Get our HID descriptor pre-parsed data
    82             PreParsedData = Win32.Utils.RawInput.GetPreParsedData(hRawInputDevice);
    83             if (PreParsedData == IntPtr.Zero)
    84             {
    85                 throw new Exception("HidDevice: GetPreParsedData failed: " + Marshal.GetLastWin32Error().ToString());
    86             }
    87 
    88             //Fetch device info
    89             iInfo = new RID_DEVICE_INFO();
    90             if (!Win32.Utils.RawInput.GetDeviceInfo(hRawInputDevice, ref iInfo))
    91             {
    92                 throw new Exception("HidDevice: GetDeviceInfo failed: " + Marshal.GetLastWin32Error().ToString());
    93             }
    94 
    95             //Open our device from the device name/path
    96             SafeFileHandle handle = Win32.Function.CreateFile(Name,
    97                 Win32.FileAccess.NONE,
    98                 Win32.FileShare.FILE_SHARE_READ | Win32.FileShare.FILE_SHARE_WRITE,
    99                 IntPtr.Zero,
   100                 Win32.CreationDisposition.OPEN_EXISTING,
   101                 Win32.FileFlagsAttributes.FILE_FLAG_OVERLAPPED,
   102                 IntPtr.Zero
   103                 );
   104 
   105             //Check if CreateFile worked
   106             if (handle.IsInvalid)
   107             {
   108                 throw new Exception("HidDevice: CreateFile failed: " + Marshal.GetLastWin32Error().ToString());
   109             }
   110 
   111             //Get manufacturer string
   112             StringBuilder manufacturerString = new StringBuilder(256);
   113             if (Win32.Function.HidD_GetManufacturerString(handle, manufacturerString, manufacturerString.Capacity))
   114             {
   115                 Manufacturer = manufacturerString.ToString();
   116             }
   117 
   118             //Get product string
   119             StringBuilder productString = new StringBuilder(256);
   120             if (Win32.Function.HidD_GetProductString(handle, productString, productString.Capacity))
   121             {
   122                 Product = productString.ToString();
   123             }
   124 
   125             //Get attributes
   126             Win32.HIDD_ATTRIBUTES attributes = new Win32.HIDD_ATTRIBUTES();
   127             if (Win32.Function.HidD_GetAttributes(handle, ref attributes))
   128             {
   129                 VendorId = attributes.VendorID;
   130                 ProductId = attributes.ProductID;
   131                 Version = attributes.VersionNumber;
   132             }
   133 
   134             handle.Close();
   135 
   136             //Get capabilities
   137             HidStatus status = Win32.Function.HidP_GetCaps(PreParsedData, ref iCapabilities);
   138             if (status != HidStatus.HIDP_STATUS_SUCCESS)
   139             {
   140                 throw new Exception("HidDevice: HidP_GetCaps failed: " + status.ToString());
   141             }
   142 
   143             //Get input button caps if needed
   144             if (Capabilities.NumberInputButtonCaps > 0)
   145             {
   146                 iInputButtonCapabilities = new HIDP_BUTTON_CAPS[Capabilities.NumberInputButtonCaps];
   147                 ushort buttonCapabilitiesLength = Capabilities.NumberInputButtonCaps;
   148                 status = Win32.Function.HidP_GetButtonCaps(HIDP_REPORT_TYPE.HidP_Input, iInputButtonCapabilities, ref buttonCapabilitiesLength, PreParsedData);
   149                 if (status != HidStatus.HIDP_STATUS_SUCCESS || buttonCapabilitiesLength != Capabilities.NumberInputButtonCaps)
   150                 {
   151                     throw new Exception("HidDevice: HidP_GetButtonCaps failed: " + status.ToString());
   152                 }
   153             }
   154 
   155             //Get input value caps if needed
   156             if (Capabilities.NumberInputValueCaps > 0)
   157             {
   158                 iInputValueCapabilities = new HIDP_VALUE_CAPS[Capabilities.NumberInputValueCaps];
   159                 ushort valueCapabilitiesLength = Capabilities.NumberInputValueCaps;
   160                 status = Win32.Function.HidP_GetValueCaps(HIDP_REPORT_TYPE.HidP_Input, iInputValueCapabilities, ref valueCapabilitiesLength, PreParsedData);
   161                 if (status != HidStatus.HIDP_STATUS_SUCCESS || valueCapabilitiesLength != Capabilities.NumberInputValueCaps)
   162                 {
   163                     throw new Exception("HidDevice: HidP_GetValueCaps failed: " + status.ToString());
   164                 }
   165             }
   166 
   167 
   168         }
   169 
   170         /// <summary>
   171         /// Dispose is just for unmanaged clean-up.
   172         /// Make sure calling disposed multiple times does not crash.
   173         /// See: http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface/538238#538238
   174         /// </summary>
   175         public void Dispose()
   176         {
   177             Marshal.FreeHGlobal(PreParsedData);
   178             PreParsedData = IntPtr.Zero;
   179         }
   180 
   181         /// <summary>
   182         /// Print information about this device to our debug output.
   183         /// </summary>
   184         public void DebugWrite()
   185         {
   186             Debug.WriteLine("================ HID =========================================================================================");
   187             Debug.WriteLine("==== Name: " + Name);
   188             Debug.WriteLine("==== Manufacturer: " + Manufacturer);
   189             Debug.WriteLine("==== Product: " + Product);
   190             Debug.WriteLine("==== VendorID: 0x" + VendorId.ToString("X4"));
   191             Debug.WriteLine("==== ProductID: 0x" + ProductId.ToString("X4"));
   192             Debug.WriteLine("==== Version: " + Version.ToString());
   193             Debug.WriteLine("==============================================================================================================");
   194         }
   195 
   196     }
   197 
   198 }