Черемнов Дмитрий
Junior Member / Новичок
Участник № / Member № 721
отправлено / posted
Добрый день !
Может кто-нибудь подскажет - как корректно написать код работы с событиями Win32 в функциях RWH.dll (приветствуется любая реализация - Visual C++, C++Builder, Delphi). Были попытки: 1. Написать драйвер сетевого обмена (Winsock2). (событие на прием пакета не обрабатывается). 2. Создать окно (например, окно настройки драйвера). Окно создается, но 'зависает' (таже проблема, события не обрабатываются). Если же пишем свою обработку событий, то 'подвисает Trace Mode'. Пример ниже. В Rwh.dll вызов MainFunc().
if (RegisterClass(&WndClass) != 0) { hWindow = CreateWindow(sClassName, "Program1", WS_OVERLAPPEDWINDOW, 100,100, 100,100, 0,0, hInstance,0); if (hWindow != 0) { ShowWindow(hWindow, CmdShow); UpdateWindow(hWindow); while (GetMessage(&msgMessage,0,0,0)) { TranslateMessage(&msgMessage); DispatchMessage(&msgMessage); //где и как требуется передать управление Trace Mode ? } exit(msgMessage.wParam); } else { MessageBox(0,"Cannot create window","Error",MB_OK); } } else MessageBox(0,"Cannot register class","Error",MB_OK); } //------------------------------------------------
Сообщения / Posts 2 | Из / From: Казахстан
| IP / IP: IP адрес / IP address |
отправлено / posted
Очередь сообщений создается для каждого потока. В МРВ несколько потоков, в т.ч. один для обработки драйвера rwh, но сам цикл обработки сообщений заключен в сервере МРВ. Теоретически, можно перехватывать оконные сообщения, но тогда скорее всего нарушится синхронизация с МРВ и приложение зависнет (в лучшем случае), или упадет (в худшем). Можно при старте драйвера rwh_start() создавать свой отдельный поток (см. ф-цию Win32 API CreateThread()) и в нее уже писать свой код, как в MainFunc() из примера. Такой вариант будет работать, но тогда необходимо самому позаботиться о синхронизации, когда МРВ будет останавливаться (rwh_stop), корректно закрывать окно и завершать свой поток. Не совсем понятно - зачем вообще в работающем МРВ показывать какое-то окно?! Если окно с настройками, то лучше сделать как всегда - настройки вынести в файл, который правится руками (через текстовый редактор), или специальной самописной программой-конфигуратором. Если нужно менять настройки в режиме реального времени, то для этого проще сделать каналы для передачи параметров в драйвер. Драйверы сетевого обмена с использованием сокетов Winsock2 прекрасно работают, только не нужно делать синхронизацию на основе обработчиков оконных событий! Например - можно использовать функцию select():
code:
bool Recv(char* rbuf, unsigned int length, unsigned int& actual, int timeout /* ms */) { timeval t; t.tv_sec = timeout / 1000; t.tv_usec = (timeout - t.tv_sec*1000) * 1000; fd_set fr; FD_ZERO(&fr); FD_SET(_cs, &fr); unsigned int read = 0; int n = 0; while ( read < length ) { n = select(1, &fr, 0, 0, &t); if ( n != 1 ) return false; // timeout // n = recv(_cs, rbuf + read, length - read, MSG_PEEK); if (n == SOCKET_ERROR) return false; for (unsigned int c=read; c<(read+n); c++) { if (rbuf[c]=='\r') { recv(_cs, rbuf + read, length - read, 0); actual = read + c + 1; return true; } } recv(_cs, rbuf + read, length - read, 0); read += n; } return true; }
Или ioctlsocket() - пример:
code:
DWORD time_left = receive_wait_time; DWORD len = 0; while (time_left > 0) { len = 0; ioctlsocket(source.socket, FIONREAD, &len); if (len > 0) break; time_left -= receive_check_interval; Sleep(receive_check_interval); } if (len == 0) { *log << "nothing received" << std::endl; actual_count = 0; return 0; } int recvd = recv(source.socket, rbuf, to_recv, 0); if (recvd == SOCKET_ERROR) { *log << Logger::error << "recv failed with error " << WSAGetLastError() << std::endl; actual_count = 0; log->pop_func_name(); return 0; }
Какой способ Вы выберете - решать Вам: первый не вызывает Sleep(), поэтому вроде лучше, но второй - тоже нормально работает.
Сообщения / Posts 17321 | Из / From: Россия
| IP / IP: IP адрес / IP address |