nyholku / purejavahidapi

Other
120 stars 69 forks source link

Windows 7 getHidDeviceInfo().getSerialNumberString() returns "?" #35

Closed zbrowning closed 7 years ago

zbrowning commented 7 years ago

getHidDeviceInfo().getSerialNumberString() returns "?" on a Windows 7 box versus a Raspi 3 where I get "BS002089-2.2".

I'm using 0.0.10.

Any ideas?

Thanks.

nyholku commented 7 years ago

Hi, sorry, no clue. I don't have a device with serial number so I cannot test this.

If you look at the code it is very straight forward:

            Properties p = new Properties();
            p.load(new StringReader(udev_device_get_sysattr_value(hid_dev, "uevent")));

            <snip>

            m_ProductString = (String) p.get("HID_NAME");
            m_SerialNumberString = (String) p.get("HID_UNIQ");

So if the product string is ok, I don't have a clue why the serial number would not be ok, unless 'udev_device_get_sysattr_value' does not support that or for that particular device.

I don't really know the ins and outs of udev, this part of the code knowledge was more or less directly lifted from the signal11 HIDAPI so I expected and still expects that it should be.

wbr Kusti

sp20 commented 7 years ago

I suppose @zbrowning is using a new version of JNA library, as version 4.0.0 does not work in Raspbian. I came across the similar bug with ManufacturerString and ProductString. The problem is caused by changed logic of Native.toString() method which is called in line #71 of purejavahidapi.windows.HidDeviceInfo.

if (HidD_GetSerialNumberString(handle, wstr, sizeofWstr))
    m_SerialNumberString = Native.toString(wstr, "utf-16le");

The problem is gone if you change the type of wstr from byte[] to char[]. The declarations of HidD_GetSerialNumberString, HidD_GetManufacturerString and HidD_GetProductString should be corrected accordingly. Like this: boolean HidD_GetManufacturerString(HANDLE HidDeviceObject, char[] Buffer, int BufferLength); Here are patched files: windows_files.zip

nyholku commented 7 years ago

Hi, thanks for debugging and contributing, I will try to merge these and release a new version soon.

Vzor- commented 7 years ago

I can confirm that JNA 4.0 -> 4.2 does cause problems and that they can be fixed with the byte to char solution. I had this issue with manufacturer name. However, even after the fix my serial numbers are all 1.0, 9999 or null, from what I can tell this is the actual value, hidViewer just leaves the field blank.

Vzor- commented 7 years ago

I fixed the malformed strings by changing native.tostring to just new String, I opened an issue https://github.com/java-native-access/jna/issues/759 As for the strange hardware serial number, they are now reporting correctly, but from what I can tell the serial numbers are largely useless. The only HID I had that had one, had it set to '???????' and usbView agreed with that output.

tresf commented 7 years ago

To summarize the fix, the memory holds a wchar_t[] and JNA's Native.toString has been improved in recent versions to stop reading bytes when it lands on a null character.

The new JNA behavor works fine for non-Windows platforms, but is simply the wrong function to use on platforms where wide characters are encoded as UTF-16 because in UTF-16, "My HID Device" is stored in memory as "M", <null>, "y", <null>, ...", etc so new JNA versions Native.toString now return a new UTF-16LE string that only contains the byte value of "M" and no following null which is invalid.

But as the upstream bug explains, this was wrong anyway. The length of the data returned is misinterpreted without knowledge of its length as <null>, <null> is a valid UTF-16 character.

The patch -- as recommended by the JNA team -- fixes this permanently by using the Pointer.getWideString function.

As @Vzor- mentions, this only fixes the original issue description. The parts about HidD_GetSerialNumberString returning data such as ????? (question marks) are invalid as that's what reads directly out of memory even with the patch applied.

Fixed in #37.