Сообщение WM_COMMNOTIFY
Сообщение WM_COMMNOTIFY отправляется драйвером COM-порта в функцию окна и служит извещением об изменении состояния COM-порта. Такое сообщение может поступать в функцию окна при наполнении входной очереди до определенного порогового значения, изменении состояния сигналов DTR, RI, RTS и т. д.
Параметр wParam сообщения WM_COMMNOTIFY определяет идентификатор COM-порта, вызвавшего отправку сообщения.
Через младшее слово параметра lParam функция окна получает число, по которому можно судить о причине посылки сообщения WM_COMMNOTIFY. Это число может быть комбинацией следующих кодов извещения:
Код извещения | Описание | ||
CN_EVENT | Произошло событие, разрешенное в слове событий COM-порта. Эти события разрешаются вызовом функции SetCommEventMask. После прихода сообщения WM_COMMNOTIFY с кодом извещения CN_EVENT приложение должно вызвать функцию GetCommEventMask, чтобы определить, какое именно событие произошло и сбросить событие | ||
CN_RECEIVE | Очередь приемника содержит больше, чем cbWriteNotify байт. Пороговое значение cbWriteNotify задается одним из параметров функции EnableCommNotification | ||
CN_TRANSMIT | Очередь передатчика содержит меньше, чем cbOutQueue байт. Пороговое значение cbOutQueue задается одним из параметров функции EnableCommNotification |
Если приложение обработало поступившее ему сообщение WM_COMMNOTIFY, оно должно возвратить нулевое значение.
Сообщение WM_COMMNOTIFY с кодом извещения CN_EVENT передается только тогда, когда слово состояния событий изменяет свое значение. Приложение, которое принимает сообщение WM_COMMNOTIFY, должно каждый раз очищать слово состояния событий, для того чтобы гарантировать получение сообщений в дальнейшем.
Использование функции EnableCommNotification для разрешения передачи сообщений WM_COMMNOTIFY с кодами извещения CN_RECEIVE и CN_TRANSMIT может вызвать генерацию ошибочных сообщений WM_COMMNOTIFY, для которых параметр NotifyStatus равен нулю. При обмене данными на высоких скоростях это может привести к аварийной ситуации и даже перезагрузке компьютера.
Для решения этой проблемы можно использовать следующие методы:
Игнорировать все сообщения WM_COMMNOTIFY, для которых параметр NotifyStatus равен нулю
Не использовать сообщения WM_COMMNOTIFY для событий CN_RECEIVE и CN_TRANSMIT
Разрешить сообщение CN_EVENT для события EV_RXCHAR с помощью функций SetCommEventMask и EnableCommNotification. Сообщение формируется при поступлении во входную очередь очередного символа. Функцию EnableCommNotification следует вызывать с параметрами cbWriteNotify и cbOutQueue -1, чтобы сообщения CN_RECEIVE и CN_TRANSMIT не посылались. Этот метод продемонстрирован в приложении TTY из Windows Software Development Kit (SDK)
Вместо использования функции EnableCommNotification приложение должно само периодически опрашивать входной буфер на наличие в нем принятых данных. Опрос можно производить по таймеру или в цикле обработки сообщений
Заменить драйвер последовательного асинхронного адаптера COMM.DRV.
Событие CN_RECEIVE формируется в тех случаях, когда количество байт во входной очереди превышает пороговое значение cbWriteNotify, установленное функцией EnableCommNotification, или когда истекло время (тайм-аут). После формирования события CN_RECEIVE в случае превышения пороговой величины cbWriteNotify другие сообщения CN_RECEIVE не будут генерироваться до тех пор, пока количество байт во входной очереди не станет меньше значения cbWriteNotify и не превысит ее снова.
Сообщение CN_TRANSMIT создается аналогично CN_RECEIVE. Порог устанавливается параметром cbOutQueue функции EnableCommNotify. Когда количество символов в выходной очереди становится меньше, чем cbOutQueue, формируется сообщение CN_TRANSMIT. Другие сообщения CN_TRANSMIT не будут посылаться до тех пор, пока в буфере не станет больше, чем cbOutQueue символов.
Однако, если прерывания поступают достаточно быстро, дополнительные сообщения CN_RECEIVE (или CN_TRANSMIT) могут посылаться до того, как количество символов в выходной очереди станет больше, чем cbWriteNotify. Эти сообщения можно пропускать (игнорировать), однако они могут послужить причиной перезагрузки системы.
Ниже приведен фрагмент обработчика сообщения WM_COMMNOTIFY:
//==========================================================
// Функция окна WndProc
//==========================================================
LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch( message )
{
case WM_COMMNOTIFY:
{
if(CN_EVENT & LOWORD( lParam ) == CN_EVENT)
{
GetCommEventMask(COMDEV( npTTYInfo ), EV_RXCHAR);
return(TRUE);
}
else if(CN_RECEIVE & LOWORD( lParam ) == CN_RECEIVE)
{
return(TRUE);
}
else if(CN_TRANSMIT & LOWORD( lParam ) == CN_TRANSMIT)
{
return(TRUE);
}
else if(LOWORD( lParam ) == 0)
return(TRUE);
}
default:
return(DefWindowProc(hwnd, message, wParam, lParam));
}
}
При загрузке драйвера последовательного асинхронного адаптера он вызывает функцию CreateSystemTimer и создает таймер, посылающий сообщения драйверу каждые 100 миллисекунд. Обрабатывая сообщения таймера, драйвер просматривает состояние всех открытых COM-портов и проводит проверку тайм-аута. Период таймера изменить нельзя.