CreateFileA fails to open HID device in Windows

10

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.

windows
usb
driver
hid
hidapi
asked on Stack Overflow May 13, 2016 by P i • edited May 23, 2017 by Community

2 Answers

1

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.

0

You're right: ERROR_SHARING_VIOLATION will occur if some other app already opened this device. You need to call CreateFileW API like this:

DWORD desired_access = GENERIC_WRITE | GENERIC_READ;
DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
::CreateFileW(deviceInterfacePath, desired_access, share_mode, 0, OPEN_EXISTING, 0, 0);

If you don't provide dwShareMode then it means that you're trying to open device exclusively. Which can fail if other app (new Windows version that maybe supports these kind of devices natively) already opened this device for its use.

Note about Keyboard and Mouse devices: you can also call ::CreateFileW without even setting desired_access (use zero value): in this case you can use HidD_GetManufacturerString/HidD_GetProductString/HidD_GetSerialNumberString/HidD_GetAttributes (and maybe some others) HID methods with returned handle. But you cannot read/write data to such device. This should be useful if you need to acquire name or VID/PID for HID keyboard/mouse.

Here is list of HID device types and their access modes on Windows.

answered on Stack Overflow Oct 26, 2020 by DJm00n

User contributions licensed under CC BY-SA 3.0