// ***** Описание на C++ *****
void CALLBACK CompletionROUTINE(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);
// ***** Описание на Delphi *****
TWSAOverlappedCompletionRoutine =
procedure(dwError: DWORD; cbTransferred: DWORD; lpOverlapped: PWSAOverlapped; dwFlags: DWORD); stdcall;
При использовании процедур завершения в функцию WSARecv
также нужно передавать указатель на запись TWSAOverlapped
через параметр lpOverlapped
, но значение поля hEvent
этой структуры игнорируется. Вместо взведения события при завершении операции будет вызвана процедура, указанная в качестве параметра функции WSARecv
. Указатель на структуру, заданный при вызове WSARecv
, передается в процедуру завершения через параметр lpOverlapped
. Смысл остальных параметров очевиден: dwError
— это код ошибки (или ноль, если операция завершена успешно), cbTransferred
— число полученных байтов (само полученное сообщение копируется в буферы, указанные при вызове функции WSARecv
), a dwFlags
— флаги.
Процедура завершения всегда выполняется в той нити, которая инициировала начало операции перекрытого ввода-вывода. Но система не может прерывать нить для выполнения процедуры завершения в любой удобный ей момент — нить должна перейти в состояние ожидания. В это состояние ее можно перевести, например, с помощью функции SleepEx
, имеющей следующий прототип:
function SleepEx(dwMilliseconds: DWORD; bAlertable: BOOL); DWORD;
Функция SleepEx
является частью стандартного API системы и импортируется модулем Windows. Она переводит нить в состояние ожидания. Параметр dwMilliseconds
задает время ожидания в миллисекундах (или значение INFINITE
для бесконечного ожидания). Параметр bAlertable указывает, допустимо ли прерывание состояния ожидания для выполнения процедуры завершения. Если bAlertable
равен False
, функция SleepEx
ведет себя так же как функция Sleep
, т. е. просто приостанавливает работу нити на заданное время. Если bAlertable
равен True
, нить может быть выведена системой из состояния ожидания раньше, чем истечет заданное время, если возникнет необходимость выполнить процедуру завершения. О причине завершения ожидания программа может судить по результату, возвращаемому функцией SleepEx
: ноль в случае завершения по тайм-ауту и WAIT_IO_COMPLETION
в случае завершения из-за выполнения процедуры завершения (в последнем случае сначала выполняется процедура завершения, а потом только происходит возврат из функции SleepEx
). Если завершились несколько операций перекрытого ввода-вывода, в результате выполнения SleepEx
будут вызваны процедуры завершения для всех этих операций.
Существует также возможность ожидать выполнения процедуры завершения одновременно с ожиданием взведения событий с помощью функции WSAWaitForMultipleEvents
. Напомним, что у этой функции также есть параметр fAlertable
. Если задать его равным True
, то при необходимости выполнения процедуры завершения функция WSAWaitForMultipleEvents
, подобно функции SleepEx
, выполняет эту процедуру и возвращает WAIT_IO_COMPLETION
.