WinUSB Read/Write with Overlapped I/O

2k views Asked by At

Does anyone have suggestions for using the WinUSB API to do overlapped read/write? The code that I wrote is always timing out - I suspect that I am using the API incorrectly to do overlapped read/write. Does anyone have any suggestions?

void MultiBlockTransfer(
    PrintParameters& parameters, 
    HANDLE hFile, 
    LARGE_INTEGER fileSize)
{
    const size_t BlockSize = parameters.PipeOutPacketSize * 8;

    LocalBuffer localBuffer(::LocalAlloc(LPTR, BlockSize));

    UCHAR* fileBuffer = (UCHAR*) localBuffer.GetBuffer();

    DWORD bytesRead = 0;

    DWORD totalBytesWritten = 0;

    do
    {
            if (!::ReadFile(hFile, fileBuffer, (DWORD) BlockSize, &bytesRead, NULL))
    {
        return;
    }

    if (bytesRead == 0)
    {
        break;
    }

    ULONG lengthTransferred = 0;

    OVERLAPPED overlappedWrite;
    OVERLAPPED overlappedRead;
    ZeroMemory(&overlappedWrite, sizeof(OVERLAPPED));
    ZeroMemory(&overlappedRead, sizeof(OVERLAPPED));

    Handle writeEvent(::CreateEvent(NULL, TRUE, FALSE, L"WriteUSBPipe"));
    Handle readEvent(::CreateEvent(NULL, TRUE, FALSE, L"ReadUsbPipe"));

    overlappedWrite.hEvent = writeEvent.GetHandle();
    overlappedWrite.Internal = STATUS_PENDING;
    overlappedRead.hEvent = readEvent.GetHandle();
    overlappedRead.Internal = STATUS_PENDING;

    ULONG readBlockSize = parameters.PipeOutPacketSize * 16;

    LocalBuffer localReadBuffer(::LocalAlloc(LPTR, readBlockSize));

    UCHAR* readBuffer = (UCHAR*) localReadBuffer.GetBuffer();
    ULONG lengthWritten = 0;
    ULONG lengthRead = 0;

    if (!::WinUsb_WritePipe(parameters.usbHandle, parameters.PipeOutId, fileBuffer, bytesRead, &lengthWritten, &overlappedWrite))
    {
        DWORD error = ::GetLastError();

        if (error != ERROR_IO_PENDING)
        {
            stringstream stream;
            stream << "Error writing to USB: " << LastErrorString;

            throw exception(stream.str().c_str());
        }
    }

    if (!::WinUsb_ReadPipe(parameters.usbHandle, parameters.PipeInId, readBuffer, readBlockSize, &lengthRead, &overlappedRead))
    {
        DWORD error = ::GetLastError();

        if (error != ERROR_IO_PENDING)
        {
            stringstream stream;
            stream << "Error reading from USB: " << LastErrorString;

            throw exception(stream.str().c_str());
        }
    }

    HANDLE events [] =
    {
        overlappedWrite.hEvent,
        overlappedRead.hEvent
    };

    DWORD waitResult = ::WaitForMultipleObjects(2, events, TRUE, 10000);

    switch (waitResult)
    {
    case WAIT_OBJECT_0:
        ::WinUsb_GetOverlappedResult(parameters.usbHandle, &overlappedWrite, &lengthWritten, TRUE);
        ::WinUsb_GetOverlappedResult(parameters.usbHandle, &overlappedRead, &lengthRead, TRUE);
        break;

    case WAIT_ABANDONED:
        throw exception("Wait for USB write/read abandoned");

    case WAIT_TIMEOUT:
        throw exception("Wait for USB write/read timed out.");

    case WAIT_FAILED:
        {
            stringstream stream;
            stream << "Wait for USB write/read failed: " << LastErrorString;
            throw exception(stream.str().c_str());
        }
    default:
        {
            stringstream stream;
            stream << "Wait for USB write/read failed with: " << waitResult;
            throw exception(stream.str().c_str());
        }
    }

    string readResult((char*) readBuffer);

    basic_stringstream<TCHAR> statusStream;

    totalBytesWritten += lengthTransferred;
    } while (bytesRead == BlockSize);
}
0

There are 0 answers