Вообще, потоки для коммуникации нафиг не нужны. Потоки для исполнения процессорных команд нужны. Ведь не зря они ещё виртуальными процессорами называются. Это дибилизм создавать поток, который только и делает, что ждёт окончания ввода-вывода. Более того, если посылать/принимать более одного блока сразу, то overlapped надо по-любому, даже для одного потока.
Если не хочешь с потоками связываться и рулить вводом-выводом прямо из GUI потока, есть два метода. Опробовано на Дельфи.
Метод первый, идентичен модальному диалогу, типа MessageBox. Т.е. процедура не возвращается пока IO не состоиться (либо юзер кликнет cancel). При этом сообщения (отрисовка, нажатия кнопок) доходят до всех окон.
Код
//Открываешь порт с overlapped:
hFile := CreateFile(PChar(OpenDialog1.FileName), GENERIC_READ, FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
Win32Check(hFile <> INVALID_HANDLE_VALUE, 'Opening file "' + OpenDialog1.FileName + '"');
try // close file
//Инициализируешь OL структуру:
FillChar(ol, SizeOf(ol), 0);
ol.hEvent := CreateEvent(nil, true, false, nil);
Win32Check(ol.hEvent, 'Creating event');
try // finalize event
можешь ещё кнопки ненужные тут пов(ы)ключать.
//зачинаешь запись:
Win32Check(WriteFile(hFile, buf, Size, Size, @ol)or (GetLastError() = ERROR_IO_PENDING), 'ReadFile');
ещё можно зафлашить выходной буффер, на всякий случай.
и ждёшь окончания в цикле:
repeat
dw := MsgWaitForMultipleObjects(1, ol.hEvent, False, INFINITE, QS_ALLINPUT);
Win32Check(dw <> $FFFFFFFF, 'MsgWaitForMultipleObjects returns ' + IntToStr(Size));
if dw = WAIT_OBJECT_0 then begin
// get number of bytes read
Win32Check(GetOverlappedResult(hFile, ol, dw, False), 'GetOverlappedResult');
//ol.Offset := ol.Offset + Size;
if dw <> Size then
raise Exception.Create('Written ' + IntToStr(dw) + ' instead of ' + IntToStr(Size))
else
Break; // а можно следующий блок данных в порт вывести или перейти в режим чтения
end;
// если мы тут, то выход из ожидания произощёл из-за сообщения в очереди потока
Application.ProcessMessages;
until false;
finally
// разрешить кнопки
CloseHandle(ol.hEvent);
end;
finally
CloseHandle(hfile);
end;
Если теперь надо послать ещё одну команду (блок данных), она встанет в очередь драйвера порта.
OverlappedIO нужно применять в любом случае, дабы не блокировать поток, обслуживающий пользовательский интерфейс. Из описания проблемы я не понял, почему следущюю команду нужно посылать до окончания предидущей, отчего такая большая задержка? Команда длинная, устройство не быстрое? Если из-за длинной команды, выж понимаете, что из-за очереди в драйвере, ваше "прерывание" дойдёт только после первого блока. Тут может потребываться разрыв связи (closefile), перед отсылкой новой команды.
Другой подход - асинхронные процедуры.
Создаёшь файл и OL точно так же. Инициацию ввода вывода снабжаешь указателем на
Код
procedure FileIOCompletionRoutine(dwErrorCode: DWORD; dwNumberOfBytesTransfered: DWORD; lpOverlapp: POVERLAPPED) stdcall;
Тут сам соорентируешься, что в ней делать. Когда всё записано/прочитано не забудь порт и событие прикрыть.
Трудность этого метода в том, что цикл обработки сообщений Дельфи, реализованный в модуле Forms.TApplication.Idle(Msg), использует для ожидания процедуру WaitMessage. Это значит, что от выходит из неё, когда приходит сообщение, игнорируя окончания ВВ. А нам нужно, чтобы запенить её на MsgWaitForMultipleObjectsEx:
Код
Done := False;
// if Done then WaitMessage;
if Done then MsgWaitForMultipleObjectsEx(0, Control {fake parameter}, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
Перекрыть метод по ООП-шному не удалось, пришлось "хакать" по-гразному: делать локальную копию системного модуля Forms.
Вообще эти методы OverlappedIO всем хороши, еслибы билли и тут не напакостил. Если дрыгать окно мышой, или ресайзить управление переходит модальной процедуре виндов, реализованной по типу нашего первого метода. Поэтому, пока пользователь не отпустит мышку, управление будет бегать в системном цикле, а не в нашем, не давая нам возможности проверить OverlappedResult ВВ. Более того, эта нелепая системная процедура виндов, как и борландовская, по какой-то непонятной причине ожидает сообщений (отпусти мышку) через WaitForMessage, вместо MsgWaitForMultipleObjectsEx. Поэтому, асинхронные IOCompletion события до нас также не доходят. Полагаю, эта та самая причина, по которой Windows Explorer приостанавливает копирование файлов, если прогресс-бар схватить мышой. То есть, окна рисуются, кнопки реагируют, а IO не идёт. Если это терпимо, то можно использовать. Я же, когда прогу на замену галимому Windows-терминалу делал, отдельный многобуфферный IO-поток по этой причине создавал и обменивался с ним сообщениями-буфферами. Могу выслать, если интересно.
И главное, никаких левых T-компонент не надо.