diff --git a/hook/hr.c b/hook/hr.c index 02a8642..3f71b3e 100644 --- a/hook/hr.c +++ b/hook/hr.c @@ -20,6 +20,7 @@ uint32_t hr_to_win32_error(HRESULT hr) case E_NOINTERFACE: return ERROR_INVALID_FUNCTION; case E_NOTIMPL: return ERROR_NOT_SUPPORTED; case E_OUTOFMEMORY: return ERROR_OUTOFMEMORY; + case E_PENDING: return ERROR_IO_PENDING; case E_POINTER: return ERROR_INVALID_ADDRESS; case E_UNEXPECTED: return ERROR_INTERNAL_ERROR; default: return ERROR_INTERNAL_ERROR; diff --git a/hook/iohook.c b/hook/iohook.c index aaf01f2..3284173 100644 --- a/hook/iohook.c +++ b/hook/iohook.c @@ -741,7 +741,10 @@ static BOOL WINAPI iohook_ReadFile( hr = iohook_invoke_next(&irp); - if (FAILED(hr)) { + if (hr == E_PENDING) { + *lpNumberOfBytesRead = 0; + lpNumberOfBytesRead = NULL; + } else if (FAILED(hr)) { return hr_propagate_win32(hr, FALSE); } diff --git a/hooklib/uart.c b/hooklib/uart.c index fedc576..2e219b3 100644 --- a/hooklib/uart.c +++ b/hooklib/uart.c @@ -197,6 +197,33 @@ static HRESULT uart_handle_close(struct uart *uart, struct irp *irp) static HRESULT uart_handle_read(struct uart *uart, struct irp *irp) { + int requested = irp->read.nbytes; + long timeout = uart->timeouts.ReadTotalTimeoutConstant + uart->timeouts.ReadTotalTimeoutMultiplier * requested; + if (timeout > 0) { + int interval_timeout = uart->timeouts.ReadIntervalTimeout; + int t0 = GetTickCount(), it0 = t0; + int last_avail = uart->readable.pos; + while (uart->readable.pos < requested) { + Sleep(1); + int t1 = GetTickCount(); + if (t1 - t0 > timeout) { + break; + } + if (interval_timeout > 0) { + if (uart->readable.pos != last_avail) { + it0 = t1; + last_avail = uart->readable.pos; + } else if (t1 - it0 > interval_timeout) { + break; + } + } + } + } + + if (uart->readable.pos == 0) { + return E_PENDING; + } + /* This does a memmove() under the covers. Less efficient than a ring buffer, but I don't expect this to matter in the common case where the entire buffer gets drained, particularly since UARTs are decidedly