-
Вычитываю инфу с порта так:
OnceAgain:
ClearCommError(PortN, Error, @ComStat);
BytesInBuffer:= ComStat.cbInQue;
Overlapped.hEvent:= CreateEvent(nil, false, false, nil);
ReadFile(PortN, buf1, BytesInBuffer, BytesRead, @Overlapped); if WaitForSingleObject(Overlapped.hEvent,2000) <> WAIT_OBJECT_0 then Goto EndRead;
..
..
Goto OnceAgain; По ClearCommError получаю кол-во байтов в буфере, там лежит правильное число, то что я жду. В WaitForSingleObject по таймату в 2 сек. не вылетаю, но после ReadFile, BytesRead = 0, то есть прочитано реально 0 байт. После перехода "Goto OnceAgain" опять на ClearCommError, в BytesInBuffer лежит уже 0, как-будто они были прочитаны. Порт вирутальный. В чем может быть причина такого поведения?
-
> После перехода "Goto OnceAgain"
Как ты, спрашивается, туда попал, если "по таймату .. не вылетаю" ?
-
> Как ты, спрашивается, туда попал, если "по таймату .. не > вылетаю" ?
В этом и вопрос.
WaitForSingleObject(Overlapped.hEvent,2000) останавливается по событию, что ф-я ReadFile завершила свою работу, но после нее в BytesRead лежит 0
-
ReadFile - функция !
С какого перепугу ты используешь ее как процедуру ?
-
А ClearCommError не ф-я разве?
-
Ты не ответил на вопрос ..
-
> Ты не ответил на вопрос ..
зацени ;) The ReadFile function reads data from a file, starting at the position indicated by the file pointer. After the read operation has been completed, the file pointer is adjusted by the number of bytes actually read, unless the file handle is created with the overlapped attribute. If the file handle is created for overlapped input and output (I/O), the application must adjust the position of the file pointer after the read operation.
BOOL ReadFile(
HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped );
-
> POP (20.08.08 14:43) Первое, как уже говорили, надо проверить результат возвращаемый ReadFile, кстати и ClearCommError тоже.... Второе, если вызов всех функций сделан верно, все параметры переданы верно, ошибок нет или это ошибка для ReadFile (см. GetLastError) ERROR_IO_PENDING, то и в этом случае никто не гарантирует, что в BytesRead всегда будет передано верное количество прочитанных байт при использовании функции ReadFile в overlapped режиме. Для получения точного количества байт полученного в этом случае надо заменить в твоем коде WaitForSingleObject на GetOverlappedResult. Примеры кода можно найти в MSDN в топике на ReadFile
-
> то и в этом случае никто не гарантирует, что в BytesRead > всегда будет передано верное количество прочитанных байт > при использовании функции ReadFile в overlapped режиме. >
ReadFile в ovelapped, вроде как начинает операцию считывания, но вот заканчивать её надо GetOverlappedResult. Тем более что в данном случае режим отложенного чтения вообще можно не использовать - ведь данные-то то одназначно в буфере есть, зачем лишний дескриптор заводить ?
-
> tesseract © (21.08.08 13:01) [8]
> Тем более что в данном случае режим отложенного чтения вообще > можно не использовать - ведь данные-то то одназначно в буфере > есть, зачем лишний дескриптор заводить ?
Данные есть - с этим соглашусь. И даже скорее всего в этом случае (но не буду утверждать однозначно, так как это не факт) ReadFile в overlapped режиме в данном случае вернул бы true (то есть чтение в буфер достаточного размера байт числом ComStat.cbInQue). Но читать в overlapped режиме все же надо, если порт был открыт в overlapped режиме (правда автор об этом умолчал, но думаю так и есть).
-
По порядку:
1) GetOverlappedResult не работает под Win95, 98, ME, чтобы работало везде, применяется CreateEvent в паре с WaitForSingleObject, что взаимозаменяемо с GetOverlappedResult.
Приведенный выше код работает везде с любыми мобильниками, с хардварными и вирутальными COM портами. Не работает только с мобилами одной марки (видимо USB дрова левые). Причем другой не родной софт для этих моделей работает.
2) Прочитал где-то, что нужно обязательно использовать 3 разные структуры Overlapped для WriteFile , WaitCommEvent, ReadFile. Видимо это нужно при реализации с потоками, чтобы запросы к Overlapped не пересекались. Сделал на всяких пожарный, хотя у меня все по порядку выполняется, без потоков.
3) Тех моделей на которых не работает у меня нет. На тех где я тестирую (на любых портах) WriteFile, а затем WaitCommEvent завершаются с False и GetLastError выдает Error_IO_Pending, что означает, что ассинхронная операция записи и далее ожидания прилета конечного символа в пакете (SetCommMask(PortN, EV_RXFLAG)) начались. Далее WaitForSingleObject(Overlapped2.hEvent,2000) в течении 2 сек ожидает окончания ассинхронной операции.. все отрабатывается.
Конечный символ в пакете прилетел, получаю кол-во символов в буфере (готовых для чтения ReadFile) через ClearCommError. Прилетает правильное число (которое я ожидаю).
Далее ReadFile (для моделей на которых все работает, то есть почти все) сразу выдает True, GetLastError = 0, BytesRead = тоже самое число, что полученное в ClearCommError.
То есть асинхронная операция не начиналась и все за раз прочиталось, так как нужное кол-вл байт уже лежало в буфере. А значит дальнейшее ожидания события по WaitForSingleObject уже не отрабатывает, и она всегда выдает, что все отлично = WAIT_OBJECT_0
Все не так, для ReadFile, для моделей на которых не работает. В буфере лежит нужное и правильное число прилетевших байт, ReadFile выдает False, GetLastError = ERROR_IO_Pending (ассинхронная операция началась).
WaitForSingleObject(Overlapped3.hEvent,4000) (увеличил до 4 сек ожидание) сразу выдает = WAIT_OBJECT_0
То есть ничего не ожидает. Соответсвенно BytesRead = 0.
Вывод.
Может действительно в USB дровах не реализована работа с WaitForSingleObject?
-
> POP (21.08.08 15:20) [10]
> 1) GetOverlappedResult не работает под Win95, 98, ME, чтобы > работало везде, применяется CreateEvent в паре с WaitForSingleObject, > что взаимозаменяемо с GetOverlappedResult.
> Далее ReadFile (для моделей на которых все работает, то > есть почти все) сразу выдает True, GetLastError = 0, BytesRead > = тоже самое число, что полученное в ClearCommError. > > То есть асинхронная операция не начиналась и все за раз > прочиталось, так как нужное кол-вл байт уже лежало в буфере. > А значит дальнейшее ожидания события по WaitForSingleObject > уже не отрабатывает, и она всегда выдает, что все отлично > = WAIT_OBJECT_0
В идеале так и должно быть.
Про GetOverlappedResult - возвращает число переданных операцией байт (в данном случае прочитанных) Совет для нерабочего случая (не правильно это, но что-то посоветовать еще трудно без подробного кода и отладки) - забудь про BytesRead в случае для ReadFile в overlapped режиме,по крайней мере если ReadFile вернул false. Так как байты уже в буфере, то считай, что прочитал все что в cbInQue после WaitForSingleObject(Overlapped3.hEvent,4000) если результат = WAIT_OBJECT_0
Другого посоветовать не могу в твоей ситуации. И сказать что-то о кривых дровах тоже. Попробуй....проверь что будет в буфере.
Вариант второй и более верный на мой взгляд для твоего спорного случая - Работать не в overlapped режиме, порт открывать без флага FILE_FLAG_OVERLAPPED, тогда и для чтения и записи не надо делать overlapped вызовов. Тогда в случае успешного чтения BytesRead будет содержать верное число байт.
-
> забудь про BytesRead в случае для ReadFile в overlapped > режиме,по крайней мере если ReadFile вернул false.
Хмм.. надо попробовать. Отпишу как проверю, заодно поставлю GetOvelappedResult, после WaitForForSibgleObject = WAIT_OBJECT_0, чтобы посмотреть какой количество байт она выдаст.
Сразу вопрос, если ReadFile возвращает False, то впоследствие (когда сработает WaitForForSibgleObject = WAIT_OBJECT_0) Винда должна заполнить переменную BytesRead правильным кол-вом байт.
Должна ли BytesRead быть глобальной переменной в этом случае? Она у меня локальная в данный момент.
-
> если ReadFile возвращает False, то
.. то если ты в полном трезвоздравомыслии задействовал overlapped mode, ты первым делом обязан проверить, а не равен ли GetLastError значению ERROR_IO_PENDING !
А ты даже не почесался это сделать)
-
> то если ты в полном трезвоздравомыслии задействовал overlapped > mode, ты первым делом обязан проверить, а не равен ли GetLastError > значению ERROR_IO_PENDING !А ты даже не почесался это сделать)
А зачем?
Ведь ReadFile для большинства случаев сразу возвращает True, так как я запрашиваю заранее известное кол-во байтов уже лежащих в буфере, готовых для чтения.
Да и для случая False, нет смысла проверять на ERROR_IO_PENDING в ReadFile, так-как такая проверка на завершенность чтения проводиться в WaitForSingleObject.
-
> А зачем?
Что "зачем" ? чесаться "зачем" ? Или что ?
И какое еще нахрен "большинство случаев", если тебе черным по белому сказано насчет GetLastError ?
-
> какое еще нахрен "большинство случаев", если тебе черным > по белому сказано насчет GetLastError ?
Я уже написал, что ReadFile либо по True выходит, в этом случае GetLastError = 0, либо по False, в этом случае в GetLastError лежит ERROR_IO_PENDING, после этого в обоих случаях WaitForSingleObject выдает о завершенности ассинхронной ситуации. Ео для второго случая в BytesRead лежит 0.
Еще вопросы?
-
> POP (21.08.08 19:20) [16]
> либо по False, в этом случае в GetLastError лежит ERROR_IO_PENDING
А если во время или даже перед чтением в другом потоке закрыть Handle порта? Ошибка будет, но другая. Так что проверить на ERROR_IO_PENDING надо, ошибки всякие бывают.
> заодно поставлю GetOvelappedResult, после WaitForForSibgleObject > = WAIT_OBJECT_0,
Напиши - интересно, потому что ту ситуацию, которую ты описываешь в
> POP (21.08.08 15:20) [10]
- это неправильное поведение, или ошибка программы или действительно возможно есть ньюансы для каких-то моделей телефонов. Так что если напишешь и еще укажешь спорные модели телефонов - буду благодарен.
-
> POP (21.08.08 17:21) [12]
> заодно поставлю GetOvelappedResult, после WaitForForSibgleObject > = WAIT_OBJECT_0, чтобы посмотреть какой количество байт > она выдаст.
Кстати, забыл сказать, если Event не ManualReset как у тебя
> Overlapped.hEvent:= CreateEvent(nil, false, false, nil);
то с GetOvelappedResult после WaitForForSibgleObject возможно могут возникнуть проблемы.
-
> Вариант
Спасибо за совет игнорировать то, что выдает ReadFile.
Все работает.
Если ReadFile выдает Fail и GetLastError = ERROR_IO_Pending, то после ожидания окончания ассинхронной операции по WaitForSingleObject = WAIT_OBJECT_0 в переменной BytesRead ничего не лежит, она не заполняется виндой, заполняется только если ReadFile выдает True.
Если после удачного ожидания по WaitForSingleObject вызвать GetOvelappedResult, то она выдаст правильное число байт, которое лежало в буфере по ClearCommError.
Но я GetOvelappedResult не юзаю из-за неуниверсальности, поэтому просто использую то число, которое выдало ClearCommError (при условии, что WaitForSingleObject отработал нормально)
Так, что все пашет и вертиться сейчас.
|