timeoutusbnonblockinghidoverlapped-io

How to perform a non-blocking write to a USB HID device?


I have a USB device that identifies as a HID peripheral. I communicate with it using the ReadFile and WriteFile Win32 API functions.

Occasionally the device gets "stuck" and does not respond, and needs to be unplugged and replugged. That's not a problem in and of itself, but it causes the call to WriteFile to block until the device is unplugged, and that is a problem.

I have read that I can use overlapped I/O to prevent this, but it doesn't work. The call to WriteFileEx still blocks!

Code fragment:

HANDLE hFCreateFileW(devicePath, NULL, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
OVERLAPPED overlapped = {0};
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!WriteFileEx(hFile, buffer, length, &overlapped, nullptr))
    return FALSE;
for (int elapsed = 0; !HasOverlappedIoCompleted(&overlapped); elapsed++) {
    std::this_thread::sleep_for(1ms);
    if (elapsed > READ_TIMEOUT_MS)
        return FALSE;
}

How can I force writes to timeout instead of blocking forever?

(NOTE: The solution needs to work on all versions of Windows from XP onwards.)


Solution

  • According to CreateFileW documentation it is required to set FILE_FLAG_OVERLAPPED in dwFlagsAndAttributes argument to enable non-blocking operations for a file.

    So you should open file as

    HANDLE hFile = CreateFileW(devicePath, NULL, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    

    otherwise operations on file are still serialized even when OVERLAPPED is passed.