This is topic Cобытия Win32 в функциях RWH.dll in forum Драйверы / Device Drivers at Форум TRACE MODE: техническая поддержка.


To visit this topic, use this URL:
http://forum.adastra.ru/ultimatebb.php/ubb/get_topic/f/14/t/000084.html

Posted by Черемнов Дмитрий (Участник № / Member № 721) on :
 
Добрый день !

Может кто-нибудь подскажет -
как корректно написать код работы с событиями Win32 в функциях RWH.dll
(приветствуется любая реализация - Visual C++, C++Builder, Delphi).
Были попытки:
1. Написать драйвер сетевого обмена (Winsock2).
(событие на прием пакета не обрабатывается).
2. Создать окно (например, окно настройки драйвера).
Окно создается, но 'зависает' (таже проблема, события не обрабатываются). Если же пишем свою обработку событий, то 'подвисает Trace Mode'.
Пример ниже. В Rwh.dll вызов MainFunc().

int TestWndProc(HWND Window, int AMessage, int WParam, int LParam)
{
TMessage AMsg;
HDC hdcHDC;
TPaintStruct PaintStruct;
TRect Rect;
AMsg.Msg = AMessage;
AMsg.WParam = WParam;
AMsg.LParam = LParam;
AMsg.Result = 0;
switch (AMessage) {
case WM_PAINT: {
hdcHDC = BeginPaint(Window,&PaintStruct);
GetClientRect(Window,&Rect);
DrawText(hdcHDC,"Hello World!", -1,&Rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(Window,&PaintStruct);
break;
};
case WM_DESTROY: { PostQuitMessage(0); break; }
default : {
return (DefWindowProc(Window, AMessage, WParam, LParam));
}
}
return AMsg.Result;
}

//---------------------------------------------------------------------------
void MainFunc()
{
WndClass.style = CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = (WNDPROC)TestWndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(0,IDI_APPLICATION);
WndClass.hCursor = LoadCursor(0,IDC_ARROW);
WndClass.hbrBackground = HBRUSH(WHITE_BRUSH);
WndClass.lpszMenuName = 0;
WndClass.lpszClassName = sClassName;

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);
}
//------------------------------------------------
 
Posted by AdAstra Technical Support (Участник № / Member № 4) on :
 
Очередь сообщений создается для каждого потока. В МРВ несколько потоков, в т.ч. один для обработки драйвера 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(), поэтому вроде лучше, но второй - тоже нормально работает.
 


Новости АСУ ТП / News | SCADA / HMI | Обучение / Trainings | Свяжитесь с нами / Contact Us



Powered by Infopop Corporation
UBB.classic™ 6.7.2