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@56: //Pre-parsed HID descriptor StephaneLenclud@52: public IntPtr PreParsedData {get; private set;} StephaneLenclud@56: //Info StephaneLenclud@53: public RID_DEVICE_INFO Info { get {return iInfo;} } StephaneLenclud@53: private RID_DEVICE_INFO iInfo; StephaneLenclud@56: //Capabilities StephaneLenclud@56: public HIDP_CAPS Capabilities { get { return iCapabilities; } } StephaneLenclud@56: private HIDP_CAPS iCapabilities; StephaneLenclud@56: //Input Button Capabilities StephaneLenclud@56: public HIDP_BUTTON_CAPS[] InputButtonCapabilities { get { return iInputButtonCapabilities; } } StephaneLenclud@56: private HIDP_BUTTON_CAPS[] iInputButtonCapabilities; StephaneLenclud@58: //Input Value Capabilities StephaneLenclud@58: public HIDP_VALUE_CAPS[] InputValueCapabilities { get { return iInputValueCapabilities; } } StephaneLenclud@58: private HIDP_VALUE_CAPS[] iInputValueCapabilities; StephaneLenclud@58: StephaneLenclud@58: StephaneLenclud@56: 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@55: //Try construct and rollback if needed StephaneLenclud@55: try StephaneLenclud@55: { StephaneLenclud@55: Construct(hRawInputDevice); StephaneLenclud@55: } StephaneLenclud@55: catch (System.Exception ex) StephaneLenclud@55: { StephaneLenclud@55: //Just rollback and propagate StephaneLenclud@55: Dispose(); StephaneLenclud@55: throw ex; StephaneLenclud@55: } StephaneLenclud@55: } StephaneLenclud@55: StephaneLenclud@55: StephaneLenclud@55: /// StephaneLenclud@55: /// Make sure dispose is called even if the user forgot about it. StephaneLenclud@55: /// StephaneLenclud@55: ~HidDevice() StephaneLenclud@55: { StephaneLenclud@55: Dispose(); StephaneLenclud@55: } StephaneLenclud@55: StephaneLenclud@55: /// StephaneLenclud@55: /// Private constructor. StephaneLenclud@55: /// StephaneLenclud@55: /// StephaneLenclud@55: private void Construct(IntPtr hRawInputDevice) StephaneLenclud@55: { StephaneLenclud@52: PreParsedData = IntPtr.Zero; StephaneLenclud@58: iInputButtonCapabilities = null; StephaneLenclud@58: iInputValueCapabilities = null; StephaneLenclud@58: 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@55: throw new Exception("HidDevice: GetPreParsedData failed: " + Marshal.GetLastWin32Error().ToString()); 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@55: throw new Exception("HidDevice: GetDeviceInfo failed: " + Marshal.GetLastWin32Error().ToString()); StephaneLenclud@53: } StephaneLenclud@55: sl@25: //Open our device from the device name/path StephaneLenclud@55: SafeFileHandle handle = Win32.Function.CreateFile(Name, sl@25: Win32.FileAccess.NONE, StephaneLenclud@55: 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@55: //Check if CreateFile worked sl@25: if (handle.IsInvalid) sl@25: { StephaneLenclud@55: throw new Exception("HidDevice: CreateFile failed: " + Marshal.GetLastWin32Error().ToString()); sl@25: } StephaneLenclud@55: StephaneLenclud@55: //Get manufacturer string StephaneLenclud@55: StringBuilder manufacturerString = new StringBuilder(256); StephaneLenclud@55: if (Win32.Function.HidD_GetManufacturerString(handle, manufacturerString, manufacturerString.Capacity)) sl@25: { StephaneLenclud@55: Manufacturer = manufacturerString.ToString(); StephaneLenclud@55: } sl@25: StephaneLenclud@55: //Get product string StephaneLenclud@55: StringBuilder productString = new StringBuilder(256); StephaneLenclud@55: if (Win32.Function.HidD_GetProductString(handle, productString, productString.Capacity)) StephaneLenclud@55: { StephaneLenclud@55: Product = productString.ToString(); StephaneLenclud@55: } sl@25: StephaneLenclud@55: //Get attributes StephaneLenclud@55: Win32.HIDD_ATTRIBUTES attributes = new Win32.HIDD_ATTRIBUTES(); StephaneLenclud@55: if (Win32.Function.HidD_GetAttributes(handle, ref attributes)) StephaneLenclud@55: { StephaneLenclud@55: VendorId = attributes.VendorID; StephaneLenclud@55: ProductId = attributes.ProductID; StephaneLenclud@55: Version = attributes.VersionNumber; StephaneLenclud@55: } sl@25: StephaneLenclud@55: handle.Close(); StephaneLenclud@56: StephaneLenclud@56: //Get capabilities StephaneLenclud@56: HidStatus status = Win32.Function.HidP_GetCaps(PreParsedData, ref iCapabilities); StephaneLenclud@56: if (status != HidStatus.HIDP_STATUS_SUCCESS) StephaneLenclud@56: { StephaneLenclud@56: throw new Exception("HidDevice: HidP_GetCaps failed: " + status.ToString()); StephaneLenclud@56: } StephaneLenclud@56: StephaneLenclud@58: //Get input button caps if needed StephaneLenclud@58: if (Capabilities.NumberInputButtonCaps > 0) StephaneLenclud@56: { StephaneLenclud@58: iInputButtonCapabilities = new HIDP_BUTTON_CAPS[Capabilities.NumberInputButtonCaps]; StephaneLenclud@58: ushort buttonCapabilitiesLength = Capabilities.NumberInputButtonCaps; StephaneLenclud@58: status = Win32.Function.HidP_GetButtonCaps(HIDP_REPORT_TYPE.HidP_Input, iInputButtonCapabilities, ref buttonCapabilitiesLength, PreParsedData); StephaneLenclud@58: if (status != HidStatus.HIDP_STATUS_SUCCESS || buttonCapabilitiesLength != Capabilities.NumberInputButtonCaps) StephaneLenclud@58: { StephaneLenclud@58: throw new Exception("HidDevice: HidP_GetButtonCaps failed: " + status.ToString()); StephaneLenclud@58: } StephaneLenclud@56: } StephaneLenclud@58: StephaneLenclud@58: //Get input value caps if needed StephaneLenclud@58: if (Capabilities.NumberInputValueCaps > 0) StephaneLenclud@58: { StephaneLenclud@58: iInputValueCapabilities = new HIDP_VALUE_CAPS[Capabilities.NumberInputValueCaps]; StephaneLenclud@58: ushort valueCapabilitiesLength = Capabilities.NumberInputValueCaps; StephaneLenclud@58: status = Win32.Function.HidP_GetValueCaps(HIDP_REPORT_TYPE.HidP_Input, iInputValueCapabilities, ref valueCapabilitiesLength, PreParsedData); StephaneLenclud@58: if (status != HidStatus.HIDP_STATUS_SUCCESS || valueCapabilitiesLength != Capabilities.NumberInputValueCaps) StephaneLenclud@58: { StephaneLenclud@58: throw new Exception("HidDevice: HidP_GetValueCaps failed: " + status.ToString()); StephaneLenclud@58: } StephaneLenclud@58: } StephaneLenclud@58: StephaneLenclud@56: 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: }