public static bool QueryDeviceCapabilities(ref DeviceInformationStructure deviceInformation) { var preparsedData = new IntPtr(); try { Hid.HidD_GetPreparsedData(deviceInformation.HidHandle, ref preparsedData); Hid.HidP_GetCaps(preparsedData, ref deviceInformation.Capabilities); } catch { Debug.WriteLine("QueryDeviceCapabilities failed with error {0}", Marshal.GetLastWin32Error()); return(false); } finally { // Free up the memory before finishing Hid.HidD_FreePreparsedData(preparsedData); } return(true); }
public static void QueryDeviceCapabilities(ref DeviceInformationStructure deviceInformation) { var preparsedData = new IntPtr(); try { // Get the preparsed data from the HID driver Hid.HidD_GetPreparsedData(deviceInformation.HidHandle, ref preparsedData); // Get the HID device's capabilities var result = Hid.HidP_GetCaps(preparsedData, ref deviceInformation.Capabilities); if ((result == 0)) { return; } Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Device query results:"); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Usage: {0}", Convert.ToString(deviceInformation.Capabilities.Usage, 16)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Usage Page: {0}", Convert.ToString(deviceInformation.Capabilities.UsagePage, 16)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Input Report Byte Length: {0}", deviceInformation.Capabilities.InputReportByteLength.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Output Report Byte Length: {0}", deviceInformation.Capabilities.OutputReportByteLength.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Feature Report Byte Length: {0}", deviceInformation.Capabilities.FeatureReportByteLength.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Link Collection Nodes: {0}", deviceInformation.Capabilities.NumberLinkCollectionNodes.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Input Button Caps: {0}", deviceInformation.Capabilities.NumberInputButtonCaps.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Input Value Caps: {0}", deviceInformation.Capabilities.NumberInputValueCaps.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Input Data Indices: {0}", deviceInformation.Capabilities.NumberInputDataIndices.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Output Button Caps: {0}", deviceInformation.Capabilities.NumberOutputButtonCaps.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Output Value Caps: {0}", deviceInformation.Capabilities.NumberOutputValueCaps.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Output Data Indices: {0}", deviceInformation.Capabilities.NumberOutputDataIndices.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Feature Button Caps: {0}", deviceInformation.Capabilities.NumberFeatureButtonCaps.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Feature Value Caps: {0}", deviceInformation.Capabilities.NumberFeatureValueCaps.ToString(CultureInfo.InvariantCulture)); Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Number of Feature Data Indices: {0}", deviceInformation.Capabilities.NumberFeatureDataIndices.ToString(CultureInfo.InvariantCulture)); } catch (Exception) { // Something went badly wrong... this shouldn't happen, so we throw an exception Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> EXECEPTION: An unrecoverable error has occurred!"); throw; } finally { // Free up the memory before finishing if (preparsedData != IntPtr.Zero) { Hid.HidD_FreePreparsedData(preparsedData); } } }
public HidDevice(string path) { //device mutex lockObject = new object(); //static buffers strBuffer = new StringBuilder(256); //open device //TODO why is 0x40000000 missing from FileAttribute in PInvoke? reference = Kernel32.CreateFile(path, Kernel32.ACCESS_MASK.GenericRight.GENERIC_WRITE, Kernel32.FileShare.FILE_SHARE_READ | Kernel32.FileShare.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.CreationDisposition.OPEN_EXISTING, Kernel32.CreateFileFlags.FILE_FLAG_OVERLAPPED, Kernel32.SafeObjectHandle.Null); if (reference.IsInvalid) { return; } //overlapped fileEvent = new ManualResetEvent(false); fileOverlapped = new SafeOverlapped(fileEvent); //get preparsed data if (!Hid.HidD_GetPreparsedData(reference, out preparsedData)) { return; } //transfer buffers capabilities = Hid.HidP_GetCaps(preparsedData); inBuffer = new byte[capabilities.InputReportByteLength]; outBuffer = new byte[capabilities.OutputReportByteLength]; featureBuffer = new byte[capabilities.FeatureReportByteLength]; //dynamic caps inputValueCaps = new List <ValueCaps>(); outputValueCaps = new List <ValueCaps>(); featureValueCaps = new List <ValueCaps>(); ushort numInputCaps = capabilities.NumberInputValueCaps; ushort numOutputCaps = capabilities.NumberOutputValueCaps; ushort numFeatureCaps = capabilities.NumberFeatureValueCaps; ushort maxValueCaps = Math.Max(numInputCaps, numOutputCaps); maxValueCaps = Math.Max(maxValueCaps, numFeatureCaps); int valueCapSize = Marshal.SizeOf <ValueCaps>(); IntPtr valueCapPtr = Marshal.AllocHGlobal(maxValueCaps * valueCapSize); HidPStatus stat = Hid.HidP_GetValueCaps(ReportType.Input, valueCapPtr, ref numInputCaps, preparsedData); for (int i = 0; i < numInputCaps; i++) { ValueCaps val = Marshal.PtrToStructure <ValueCaps>(new IntPtr(valueCapPtr.ToInt64() + (i * valueCapSize))); inputValueCaps.Add(val); } stat = Hid.HidP_GetValueCaps(ReportType.Output, valueCapPtr, ref numOutputCaps, preparsedData); for (int i = 0; i < numOutputCaps; i++) { ValueCaps val = Marshal.PtrToStructure <ValueCaps>(new IntPtr(valueCapPtr.ToInt64() + i * valueCapSize)); outputValueCaps.Add(val); } stat = Hid.HidP_GetValueCaps(ReportType.Feature, valueCapPtr, ref numFeatureCaps, preparsedData); for (int i = 0; i < numFeatureCaps; i++) { ValueCaps val = Marshal.PtrToStructure <ValueCaps>(new IntPtr(valueCapPtr.ToInt64() + i * valueCapSize)); featureValueCaps.Add(val); } Marshal.FreeHGlobal(valueCapPtr); }
private void _DeviceSearchThread() { _Logger.Info("Started"); while (_Running) { var loopStart = DateTime.Now; #region Device enumeration var devices = new List <UsbDevice>(); var detailDataBuffer = IntPtr.Zero; var deviceInfoSet = IntPtr.Zero; try { int listIndex = 0; int lastError = 0; var deviceInterfaceData = new SpDeviceInterfaceData(); var systemHidGuid = new Guid(); Hid.HidD_GetHidGuid(ref systemHidGuid); deviceInfoSet = SetupApi.SetupDiGetClassDevs(ref systemHidGuid, IntPtr.Zero, IntPtr.Zero, Constants.DigcfPresent | Constants.DigcfDeviceinterface); deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData); while (SetupApi.SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref systemHidGuid, listIndex++, ref deviceInterfaceData) || (lastError = Marshal.GetLastWin32Error()) != Constants.ERROR_NO_MORE_ITEMS) { if (lastError == 0) { int bufferSize = 0; SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); detailDataBuffer = Marshal.AllocHGlobal(bufferSize); Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); if (SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero)) { var pDevicePathName = IntPtr.Add(detailDataBuffer, 4); var devicePath = Marshal.PtrToStringAuto(pDevicePathName); // Get device capabilities (to determine usage page) using (var hidHandle = Kernel32.CreateFile(devicePath, 0, Constants.FileShareRead | Constants.FileShareWrite, IntPtr.Zero, Constants.OpenExisting, 0, 0)) { var preparsedData = IntPtr.Zero; try { preparsedData = new IntPtr(); Hid.HidD_GetPreparsedData(hidHandle, ref preparsedData); var caps = new HidpCaps(); Hid.HidP_GetCaps(preparsedData, ref caps); var attrs = new HiddAttributes(); Hid.HidD_GetAttributes(hidHandle, ref attrs); // Only add the device if it has our VID, PID, and RAW usage page var deviceClass = FindDeviceClass(attrs.VendorID, attrs.ProductID, attrs.VersionNumber, caps.UsagePage); if (deviceClass != null) { var manufacturer = new StringBuilder(STRING_SIZE_LIMIT); var product = new StringBuilder(STRING_SIZE_LIMIT); var serial = new StringBuilder(STRING_SIZE_LIMIT); Hid.HidD_GetManufacturerString(hidHandle, manufacturer, STRING_SIZE_LIMIT); Hid.HidD_GetProductString(hidHandle, product, STRING_SIZE_LIMIT); Hid.HidD_GetSerialNumberString(hidHandle, serial, STRING_SIZE_LIMIT); var device = new UsbDevice(new DeviceInstance(deviceClass, devicePath, manufacturer.ToString(), product.ToString(), serial.ToString()), caps); devices.Add(device); } } finally { // Free up the memory before finishing if (preparsedData != IntPtr.Zero) { Hid.HidD_FreePreparsedData(preparsedData); } } } } } } } catch (Exception ex) { _Logger.Error(ex, "Error scanning for devices:"); devices.Clear(); } finally { // Clean up the unmanaged memory allocations and free resources held by the windows API if (detailDataBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(detailDataBuffer); } if (deviceInfoSet != IntPtr.Zero) { SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoSet); } } var addedDevices = devices.Except(_CurrentDevices); var removedDevices = _CurrentDevices.Except(devices); _CurrentDevices = devices; if (DeviceRemoved != null) { foreach (var dev in removedDevices) { _Logger.Info("Device removed: {0}", dev); DeviceRemoved(this, new DeviceEventArgs(dev.Instance)); } } if (DeviceAdded != null) { foreach (var dev in addedDevices) { _Logger.Info("Device added: {0}", dev); DeviceAdded(this, new DeviceEventArgs(dev.Instance)); } } #endregion #region Active device I/O // If we receive a request to change the active device while we are processing messages, we need to stop immediately because they are about to become invalid { byte[] msg; while (true) { byte[] response = null; // Block until SetActiveDevice finishes lock (_LockObject) { // If we created a new message queue in the call to SetActiveDevice, this will return false and we'll break out of the loop if (_ActiveDevice == null || !_MessageQueue.TryDequeue(out msg)) { break; } try { response = SendDeviceRequest(_ActiveDevice, msg); } catch (Exception ex) { _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult); } } if (response != null) { ProcessResponse(msg, response); } else { _Logger.Error("Failed to read data from device. req = {0}", FormatByteArray(msg)); } } } // Get LED config (it may have changed) { byte[] response = null; byte[] msg = CreateSimpleMessage(hid_pkt_req.HID_PKT_REQ_CONFIG_LED_GET); // Block until SetActiveDevice finishes lock (_LockObject) { if (_ActiveDevice != null) { try { response = SendDeviceRequest(_ActiveDevice, msg); } catch (Exception ex) { _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult); } } } if (response != null) { ProcessResponse(msg, response); } } // Get LED status { byte[] response = null; byte[] msg = new byte[2]; msg[0] = (byte)hid_pkt_req.HID_PKT_REQ_LED_STATUS; msg[1] = 0; var ledStatuses = new List <LedColor>(); do { lock (_LockObject) { if (_ActiveDevice != null) { try { response = SendDeviceRequest(_ActiveDevice, msg); } catch (Exception ex) { _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult); } } } if (response != null) { // Parse response for (byte i = 0; i < response[1] && i < 10; i++) { var led = new LedColor( response[i * 3 + 2], response[i * 3 + 3], response[i * 3 + 4] ); ledStatuses.Add(led); } msg[1] += 10; } } while (response != null && response[0] == (byte)hid_pkt_res.HID_PKT_RES_MORE); LedStatusReceived?.Invoke(this, new LedStatusReceivedEventArgs(ledStatuses)); } #endregion // Wait until the entire loop execution is at least 100ms var loopTime = DateTime.Now - loopStart; if (loopTime < LOOP_DELAY) { var waitTime = LOOP_DELAY - loopTime; Thread.Sleep(waitTime); } } }