Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 25 additions & 13 deletions src/serialport_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,18 +326,28 @@ bool IsClosingHandle(int fd) {

void __stdcall WriteIOCompletion(DWORD errorCode, DWORD bytesTransferred, OVERLAPPED* ov) {
WriteBaton* baton = static_cast<WriteBaton*>(ov->hEvent);
DWORD bytesWritten;
if (!GetOverlappedResult(int2handle(baton->fd), ov, &bytesWritten, TRUE)) {
errorCode = GetLastError();
ErrorCodeToString("Writing to COM port (GetOverlappedResult)", errorCode, baton->errorString);

if (errorCode) {
ErrorCodeToString("Writing to COM port (WriteIOCompletion)", errorCode, baton->errorString);
baton->complete = true;
return;
}
if (bytesWritten) {
baton->offset += bytesWritten;

// bytesTransferred is already provided by the APC completion callback.
// Do NOT call GetOverlappedResult here — MSDN explicitly states:
// "Do not use GetOverlappedResult for I/O operations that use
// ReadFileEx or WriteFileEx completion routines."
// The overlapped's hEvent holds a WriteBaton pointer (not a Windows event
// handle), so GetOverlappedResult fails with ERROR_INVALID_HANDLE on
// drivers that inspect hEvent (e.g. usbser.sys used by USB serial chips).
if (bytesTransferred) {
baton->offset += bytesTransferred;
if (baton->offset >= baton->bufferLength) {
baton->complete = true;
}
} else {
// Zero-byte completion with no error — avoid hanging in WriteThread.
baton->complete = true;
}
}

Expand Down Expand Up @@ -441,21 +451,23 @@ void __stdcall ReadIOCompletion(DWORD errorCode, DWORD bytesTransferred, OVERLAP
return;
}

// bytesTransferred is already provided by the APC completion callback.
// Do NOT call GetOverlappedResult here — MSDN explicitly states:
// "Do not use GetOverlappedResult for I/O operations that use
// ReadFileEx or WriteFileEx completion routines."
// The overlapped's hEvent holds a ReadBaton pointer (not a Windows event
// handle), so GetOverlappedResult fails with ERROR_INVALID_HANDLE on
// drivers that inspect hEvent (e.g. usbser.sys used by ESP32 native USB).

DWORD lastError;
if (!GetOverlappedResult(int2handle(baton->fd), ov, &bytesTransferred, TRUE)) {
lastError = GetLastError();
ErrorCodeToString("Reading from COM port (GetOverlappedResult)", lastError, baton->errorString);
baton->complete = true;
return;
}
if (bytesTransferred) {
baton->bytesToRead -= bytesTransferred;
baton->bytesRead += bytesTransferred;
baton->offset += bytesTransferred;
}
if (!baton->bytesToRead) {
baton->complete = true;
CloseHandle(ov->hEvent);
// Note: ov->hEvent is a baton pointer, not a Windows handle — do not CloseHandle
return;
}

Expand Down