@@ -69,6 +69,15 @@ typedef LONG NTSTATUS;
6969/* BLUETOOTH_DEVICE_NAME_SIZE from bluetoothapis.h is 256 */
7070#define MAX_STRING_WCHARS 256
7171
72+ /* For certain USB devices, using a buffer larger or equal to 127 wchars results
73+ in successful completion of HID API functions, but a broken string is stored
74+ in the output buffer. This behaviour persists even if HID API is bypassed and
75+ HID IOCTLs are passed to the HID driver directly. Therefore, for USB devices,
76+ the buffer MUST NOT exceed 126 WCHARs.
77+ */
78+
79+ #define MAX_STRING_WCHARS_USB 126
80+
7281static struct hid_api_version api_version = {
7382 .major = HID_API_VERSION_MAJOR ,
7483 .minor = HID_API_VERSION_MINOR ,
@@ -590,11 +599,22 @@ static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_n
590599 }
591600}
592601
593- static void hid_internal_get_info (const wchar_t * interface_path , struct hid_device_info * dev )
602+ /* Unfortunately, HID_API_BUS_xxx constants alone aren't enough to distinguish between BLUETOOTH and BLE */
603+
604+ #define HID_API_BUS_FLAG_BLE 0x01
605+
606+ typedef struct hid_internal_detect_bus_type_result_ {
607+ DEVINST dev_node ;
608+ hid_bus_type bus_type ;
609+ unsigned int bus_flags ;
610+ } hid_internal_detect_bus_type_result ;
611+
612+ static hid_internal_detect_bus_type_result hid_internal_detect_bus_type (const wchar_t * interface_path )
594613{
595614 wchar_t * device_id = NULL , * compatible_ids = NULL ;
596615 CONFIGRET cr ;
597616 DEVINST dev_node ;
617+ hid_internal_detect_bus_type_result result = { 0 };
598618
599619 /* Get the device id from interface path */
600620 device_id = hid_internal_get_device_interface_property (interface_path , & DEVPKEY_Device_InstanceId , DEVPROP_TYPE_STRING );
@@ -625,42 +645,45 @@ static void hid_internal_get_info(const wchar_t* interface_path, struct hid_devi
625645 https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
626646 https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
627647 if (wcsstr (compatible_id , L"USB" ) != NULL ) {
628- dev -> bus_type = HID_API_BUS_USB ;
629- hid_internal_get_usb_info (dev , dev_node );
648+ result .bus_type = HID_API_BUS_USB ;
630649 break ;
631650 }
632651
633652 /* Bluetooth devices
634653 https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
635654 if (wcsstr (compatible_id , L"BTHENUM" ) != NULL ) {
636- dev -> bus_type = HID_API_BUS_BLUETOOTH ;
655+ result . bus_type = HID_API_BUS_BLUETOOTH ;
637656 break ;
638657 }
639658
640659 /* Bluetooth LE devices */
641660 if (wcsstr (compatible_id , L"BTHLEDEVICE" ) != NULL ) {
642- dev -> bus_type = HID_API_BUS_BLUETOOTH ;
643- hid_internal_get_ble_info ( dev , dev_node ) ;
661+ result . bus_type = HID_API_BUS_BLUETOOTH ;
662+ result . bus_flags |= HID_API_BUS_FLAG_BLE ;
644663 break ;
645664 }
646665
647666 /* I2C devices
648667 https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
649668 if (wcsstr (compatible_id , L"PNP0C50" ) != NULL ) {
650- dev -> bus_type = HID_API_BUS_I2C ;
669+ result . bus_type = HID_API_BUS_I2C ;
651670 break ;
652671 }
653672
654673 /* SPI devices
655674 https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
656675 if (wcsstr (compatible_id , L"PNP0C51" ) != NULL ) {
657- dev -> bus_type = HID_API_BUS_SPI ;
676+ result . bus_type = HID_API_BUS_SPI ;
658677 break ;
659678 }
660679 }
680+
681+ result .dev_node = dev_node ;
682+
661683end :
662684 free (device_id );
663685 free (compatible_ids );
686+ return result ;
664687}
665688
666689static char * hid_internal_UTF16toUTF8 (const wchar_t * src )
@@ -699,7 +722,10 @@ static struct hid_device_info *hid_internal_get_device_info(const wchar_t *path,
699722 HIDD_ATTRIBUTES attrib ;
700723 PHIDP_PREPARSED_DATA pp_data = NULL ;
701724 HIDP_CAPS caps ;
702- wchar_t string [MAX_STRING_WCHARS ];
725+ wchar_t string [MAX_STRING_WCHARS + 1 ];
726+ ULONG len ;
727+ ULONG size ;
728+ hid_internal_detect_bus_type_result detect_bus_type_result ;
703729
704730 /* Create the record. */
705731 dev = (struct hid_device_info * )calloc (1 , sizeof (struct hid_device_info ));
@@ -733,25 +759,46 @@ static struct hid_device_info *hid_internal_get_device_info(const wchar_t *path,
733759 HidD_FreePreparsedData (pp_data );
734760 }
735761
762+ /* detect bus type before reading string descriptors */
763+ detect_bus_type_result = hid_internal_detect_bus_type (path );
764+ dev -> bus_type = detect_bus_type_result .bus_type ;
765+
766+ len = dev -> bus_type == HID_API_BUS_USB ? MAX_STRING_WCHARS_USB : MAX_STRING_WCHARS ;
767+ string [len ] = L'\0' ;
768+ size = len * sizeof (wchar_t );
769+
736770 /* Serial Number */
737771 string [0 ] = L'\0' ;
738- HidD_GetSerialNumberString (handle , string , sizeof (string ));
739- string [MAX_STRING_WCHARS - 1 ] = L'\0' ;
772+ HidD_GetSerialNumberString (handle , string , size );
740773 dev -> serial_number = _wcsdup (string );
741774
742775 /* Manufacturer String */
743776 string [0 ] = L'\0' ;
744- HidD_GetManufacturerString (handle , string , sizeof (string ));
745- string [MAX_STRING_WCHARS - 1 ] = L'\0' ;
777+ HidD_GetManufacturerString (handle , string , size );
746778 dev -> manufacturer_string = _wcsdup (string );
747779
748780 /* Product String */
749781 string [0 ] = L'\0' ;
750- HidD_GetProductString (handle , string , sizeof (string ));
751- string [MAX_STRING_WCHARS - 1 ] = L'\0' ;
782+ HidD_GetProductString (handle , string , size );
752783 dev -> product_string = _wcsdup (string );
753784
754- hid_internal_get_info (path , dev );
785+ /* now, the portion that depends on string descriptors */
786+ switch (dev -> bus_type ) {
787+ case HID_API_BUS_USB :
788+ hid_internal_get_usb_info (dev , detect_bus_type_result .dev_node );
789+ break ;
790+
791+ case HID_API_BUS_BLUETOOTH :
792+ if (detect_bus_type_result .bus_flags & HID_API_BUS_FLAG_BLE )
793+ hid_internal_get_ble_info (dev , detect_bus_type_result .dev_node );
794+ break ;
795+
796+ case HID_API_BUS_UNKNOWN :
797+ case HID_API_BUS_SPI :
798+ case HID_API_BUS_I2C :
799+ /* shut down -Wswitch */
800+ break ;
801+ }
755802
756803 return dev ;
757804}
@@ -1356,7 +1403,12 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int
13561403{
13571404 BOOL res ;
13581405
1359- res = HidD_GetIndexedString (dev -> device_handle , string_index , string , sizeof (wchar_t ) * (DWORD ) MIN (maxlen , MAX_STRING_WCHARS ));
1406+ if (dev -> device_info && dev -> device_info -> bus_type == HID_API_BUS_USB && maxlen > MAX_STRING_WCHARS_USB ) {
1407+ string [MAX_STRING_WCHARS_USB ] = L'\0' ;
1408+ maxlen = MAX_STRING_WCHARS_USB ;
1409+ }
1410+
1411+ res = HidD_GetIndexedString (dev -> device_handle , string_index , string , (ULONG )maxlen * sizeof (wchar_t ));
13601412 if (!res ) {
13611413 register_winapi_error (dev , L"HidD_GetIndexedString" );
13621414 return -1 ;
0 commit comments