EDIT: Issue reported here: https://github.com/signal11/hidapi/issues/276
Inkling is a pen-device from Wacom. (InklingReader) is an open source project that gets real-time data from it.
I'm trying to tidy up InklingReader to use HIDAPI rather than libusb (as it works at higher level: HID rather than raw USB, so is much more compact & suitable. Also libusb fails on recent OSX).
HID API a small lib: one .h, one (per-platform) .c.
My code looks like this:
unsigned short inklingVendorId = 0x056a, inklingProductId = 0x0221;
if (hid_init() == FAIL) return;
handle = hid_open(inklingVendorId, inklingProductId, nullptr);
On Windows hid_open
fails. Single stepping reveals the fail-point here:
// path = "\\\\?\\hid#vid_056a&pid_0221&mi_00&col01#8&1ea90857&0&0000#"
// "{4d1e55b2-f16f-11cf-88cb-001111000030}"
//
static HANDLE open_device(const char *path, BOOL enumerate)
{
HANDLE handle;
DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);
DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
// enumerate = 0
handle = CreateFileA(path,
desired_access,
share_mode,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
0);
int err = GetLastError(); // 5 i.e. ERROR_ACCESS_DENIED
return handle; // returns 0xffffffff i.e. INVALID_HANDLE
}
Now the HIDAPI author says "HIDAPI won't work with keyboards and mice on Windows. Windows as a security measure doesn't allow the opening of Mouse and Keyboard HIDs." (here)
And if I enumerate HID devices:
struct hid_device_info *devs, *cur_dev;
devs = hid_enumerate(inklingVendorId, inklingProductId);
cur_dev = devs;
while (cur_dev) {
DBG2("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
DBG2("");
DBG2(" Manufacturer: %ls", cur_dev->manufacturer_string);
DBG2(" Product: %ls", cur_dev->product_string);
DBG2(" Release: %hx", cur_dev->release_number);
DBG2(" Interface: %d", cur_dev->interface_number);
DBG2(" Usage Page: %d", cur_dev->usage_page);
DBG2(" Usage: %d", cur_dev->usage);
DBG2("");
cur_dev = cur_dev->next;
}
hid_free_enumeration(devs);
... I get not one but TWO entries:
Device Found
type: 056a 0221
path: \\?\hid#vid_056a&pid_0221&mi_00&col01#8&1ea90857&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
serial_number: 2B0400001C90C22A0002DD07FE8B022A
Manufacturer: Wacom, Inc.
Product: MSC Device
Release: 1256
Interface: 0
Usage Page: 1
Usage: 2
Device Found
type: 056a 0221
path: \\?\hid#vid_056a&pid_0221&mi_00&col02#8&1ea90857&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
serial_number: 2B0400001C90C22A0002DD07FE8B022A
Manufacturer: Wacom, Inc.
Product: MSC Device
Release: 1256
Interface: 0
Usage Page: 13
Usage: 2
(Note: OSX only reports the SECOND entry! On OSX there is no problem!)
Comparing path
:
path: \?\hid#vid_056a&pid_0221&mi_00&col01#8&1ea90857&0&0000#...
path: \?\hid#vid_056a&pid_0221&mi_00&col02#8&1ea90857&0&0001#...
As per http://www.usb.org/developers/hidpage/Hut1_12v2.pdf,
UsagePage/Usage = 1/2 = {Generic Desktop Controls}/{Mouse}.
UsagePage/Usage = 13/2 = {Digitizers}/{Pen}.
(EDIT: Sometimes the first path is the 1/2 and the second is the 13/2, other times it's swapped).
And HIDAPI is only taking the first one it finds.
So it looks like this should be the solution. The Inkling was exposing 2 'devices' and hidapi was taking the wrong (mouse) one, and Windows doesn't allow access to Mouse or Keyboard Devices.
So I tweak the code...
while (cur_dev) {
if (cur_dev->vendor_id == vendor_id &&
cur_dev->product_id == product_id &&
cur_dev->usage_page == 13)
{
... to get the correct entry, it should work right?
Nope, CreateFileA just raises a different error:
usage_page== 1 => Error code 5 (ERROR_ACCESS_DENIED)
usage_page==13 => Error code 32 (ERROR_SHARING_VIOLATION)
Meh. This is rather upsetting. I seem to be at a dead-end!
I've tried fiddling with CreateFileA's params, e.g. replacing GENERIC_READ | GENERIC_WRITE
with STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE
-- now it happily creates a handle. But subsequent hid_read
-s fail to collect any data.
Googling, https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/af869f90-7bda-483d-ba2d-51680073fe9f/createfile-returns-invalid-handle-while-trying-to-access-hid-device-on-windows-8-desktop-app?forum=wdk seems to contain a couple of suggested workarounds:
both toaster and firefly can work in the HID stack. toaster shows how to address the filter through a raw PDO, firefly shows how to access it with WMI. From a C perspective, I think the raw PDO is much simpler to code to, WMI is a bit nasty and complicated.
firefly
toaster
The author is recommending something in toaster, but it is a big CodeBase and I don't have experience with Windows Driver programming.
It looks as though I'm going to have to dig through a lot of very unfamiliar territory to get anything working, so before a start out I am asking here. If nobody answers and I figure it out, I will answer my own question.
The only other thing I can think of it is that maybe another process is already engaging this path. Maybe if I can terminate this process, the CreateFileA might succeed? Roel's libusb approach involves detaching kernel driver: https://github.com/roelj/inklingreader/blob/master/src/usb/online-mode.c#L98
PS Somewhere I read that if another process has already opened this device, our open has to match the permissions of this previous open. And I also read that Windows automatically opens all HID Devices upon detection.
Find out which process has an exclusive lock on a USB device handle
PPS maybe one idea is to try an alternative HID lib What is the best usb library to communicate with usb HID devices on Windows?
PPPS maybe I need to run my code as admin. But that's not a good solution.
I have seen similar behavior. The ERROR_SHARING_VIOLATION problem started to occur after upgrading to Windows 10 Anniversary Edition. The problem is only seen for USB HID devices connected when Windows is started. If you unplug and plug the USB device after Windows has started then CreateFile is successful. I haven't yet found a root cause or a solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With