WndProc(...)
{
switch (Message)
{
case WM_CREATE:
{
hEvent1=CreateEvent(NULL,false,false,NULL);
hEvent2=CreateEvent(NULL,false,false,NULL);
_beginthread(Thread1,...);
_beginthread(Thread2,...);
}
break;
case WM_KEYDOWN:
{
SetEven(hEvent1);
SetEven(hEvent2);
}
break;
...
}
}
Thread1(...)
{
...
while(1)
{
WaitForSingleObject(hEvent1, INFINITE);
...
}
...
}
Thread2(...)
{
...
while(1)
{
WaitForSingleObject(hEvent2, INFINITE);
...
}
...
}
Проблема с интерфейсом в многопоточном приложении с событиями
В приложении 3 потока. Первый основной, в нем находится оконная процедура обработки сообщений WndProc, создаются два глобальных события (hEvent1 и hEvent2) и два потока (Thread1 и Thread2). Каждому событию hEventx соответствует свой поток Threadx. Структура потоков одинакова и заключается в следующем. В потоке находится бесконечный цикл в котором вызывается ф-ия WaitForSingleObject(hEventx, INFINITE), на которой поток должен остановиться и продолжить свою работу после освобождения события. Освобождения события(SetEvent(hEventx)) происходит в основном потоке в функции WndProc при появлении сообщения о нажатии клавиши Enter на клавиатуре. При нажатии этой клавиши оба события освобождаются и потоки продолжают свою работу. Но проблема в том, что когда потоки переходят в режим ожидания события (натыкаются на WaitForSingleObject), интерфейс окна повисает. И функция WndProc не реагирует на нажатие клавиш. Хотя вызов WaitForSingleObject происходит исключительно в двух созданных потоках.
Код:
while(1)
{
while(WaitForSingleObject(hEvent1, 50) == WAIT_TIMEOUT)
{
Sleep(1);
}
...
}
{
while(WaitForSingleObject(hEvent1, 50) == WAIT_TIMEOUT)
{
Sleep(1);
}
...
}
С цифрами задания времён 50 и 1 можно поэкспериментировать.
Нет не помогло. При том тот цикл, который ты мне порекомендовал, работает, т.е. потоки работают, но интерфейс все равно виснет. От того что потоки останавливались ничего не зависело.
Код:
while(1)
{
while(WaitForSingleObject(hEvent1, 50) == WAIT_TIMEOUT)
{
Sleep(1);
}
...
}
{
while(WaitForSingleObject(hEvent1, 50) == WAIT_TIMEOUT)
{
Sleep(1);
}
...
}
ума не могу приложить, зачем здесь Sleep(1).
WaitForSingleObject сама по себе функция ожидания. :-D
если автор темы выложит полный код, проблема решится быстрее. :-D
Цитата: ШпиЁн
ума не могу приложить, зачем здесь Sleep(1).
WaitForSingleObject сама по себе функция ожидания. :-D
WaitForSingleObject сама по себе функция ожидания. :-D
Да. Похоже на то. Хотел что-то сделать, чтоб поток не вешался и внес дополнительную путаницу. Видать, ещё не проснулся когда писал это.
Возможно, флаг доступа события не EVENT_MODIFY_STATE, что требуется при использования функции SetEvent...
Цитата: ШпиЁн
если автор темы выложит полный код, проблема решится быстрее. :-D
Тут у меня код основного потока:
Код:
Controls TabControl;
void InitDialog(HINSTANCE hInstance,HWND hwnd)
{
SendMessage(GetDlgItem(hwnd,IDC_RICHEDIT22),EM_SETEVENTMASK,0,ENM_KEYEVENTS);
TabControl.Init(hInstance,hwnd,GetDlgItem(hwnd,IDC_TAB1),GetDlgItem(hwnd,IDC_RICHEDIT22));
TabControl.Add(NULL);
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HMODULE RicEdit=LoadLibrary(L"Riched20.dll");
HWND hwnd;
MSG msg;
WNDCLASS w;
memset(&w, 0, sizeof(WNDCLASS));
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.hInstance = hInstance;
w.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
w.lpszClassName = L"My Class";
w.cbWndExtra=DLGWINDOWEXTRA;
RegisterClass(&w);
hwnd=CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,NULL);
InitCommonControls();
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
InitDialog(hInstance,hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
FreeLibrary(RicEdit);
}
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
switch (Message)
{
case WM_NOTIFY:
{
MSGFILTER* lpmsgfilter = (MSGFILTER*)lparam;
switch(lpmsgfilter->nmhdr.code)
{
case TCN_SELCHANGE://TCN_SELCHANGING:
TabControl.SetCurrent();
break;
case EN_MSGFILTER:
{
if(lpmsgfilter->wParam==VK_RETURN&&lpmsgfilter->msg==WM_KEYDOWN)
{
TabControl.Current->OnEnter();
}
}
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wparam, lparam);
}
return 0;
}
void InitDialog(HINSTANCE hInstance,HWND hwnd)
{
SendMessage(GetDlgItem(hwnd,IDC_RICHEDIT22),EM_SETEVENTMASK,0,ENM_KEYEVENTS);
TabControl.Init(hInstance,hwnd,GetDlgItem(hwnd,IDC_TAB1),GetDlgItem(hwnd,IDC_RICHEDIT22));
TabControl.Add(NULL);
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HMODULE RicEdit=LoadLibrary(L"Riched20.dll");
HWND hwnd;
MSG msg;
WNDCLASS w;
memset(&w, 0, sizeof(WNDCLASS));
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.hInstance = hInstance;
w.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
w.lpszClassName = L"My Class";
w.cbWndExtra=DLGWINDOWEXTRA;
RegisterClass(&w);
hwnd=CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,NULL);
InitCommonControls();
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
InitDialog(hInstance,hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
FreeLibrary(RicEdit);
}
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
switch (Message)
{
case WM_NOTIFY:
{
MSGFILTER* lpmsgfilter = (MSGFILTER*)lparam;
switch(lpmsgfilter->nmhdr.code)
{
case TCN_SELCHANGE://TCN_SELCHANGING:
TabControl.SetCurrent();
break;
case EN_MSGFILTER:
{
if(lpmsgfilter->wParam==VK_RETURN&&lpmsgfilter->msg==WM_KEYDOWN)
{
TabControl.Current->OnEnter();
}
}
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wparam, lparam);
}
return 0;
}
Код:
class Control
{
friend class Controls;
private:
Control *Next;
HWND hwndListBox,hwndTabControl,hwndRichEdit;
HINSTANCE hInstance;
HANDLE hEvent;
Control();
~Control();
void CreateTab();
void CreateListBox();
void Create(HINSTANCE hInstance,HWND hwndTabControl,HWND hwndRichEdit,int iCount,SOCKET Sock,Controls* ThisControls);
SOCKET Connection(SOCKET Sock);
public:
SOCKET Sock;
Controls *ThisControls;
void Printf(WCHAR* s);
void Scanf(WCHAR* str);
void OnEnter();
};
class Controls
{
friend class Control;
private:
int iCount;
Control *First,*End;
HWND hwnd,hwndTabControl,hwndRichEdit;
HINSTANCE hInstance;
public:
Control *Current;
Controls();
Control* GetControl(int iPage,bool Prev);
void Add(SOCKET Sock);
bool DeleteCur();
void Init(HINSTANCE hInstance, HWND hwnd,HWND hwndTabControl,HWND hwndRichEdit);
int SetCurrent();
};
Control::~Control()
{
SendMessage(this->hwndListBox,WM_CLOSE,NULL,NULL);
int iItem=TabCtrl_GetCurSel(this->hwndTabControl);
TabCtrl_DeleteItem(this->hwndTabControl,iItem);
}
Control::Control()
{
this->Next=NULL;
this->hwndListBox=NULL;
this->hInstance=NULL;
this->hEvent=NULL;
this->ThisControls=NULL;
}
void Control::Scanf(WCHAR* str)//ф-ия ожидающая ввода текста
{
WaitForSingleObject(this->hEvent, INFINITE);
WCHAR s[100];
GetWindowText(this->hwndRichEdit,s,100);
if(wcslen(s)!=0)
{ SetWindowText(this->hwndRichEdit,L"");
this->Printf(s); }
wcscpy(str,s);
}
void Control::OnEnter(){SetEvent(this->hEvent);}
void Control::CreateTab()
{
TCITEM pitem;
pitem.mask = NULL;
pitem.iImage = -1;
pitem.lParam = 0;
TabCtrl_InsertItem(this->hwndTabControl,this->ThisControls->iCount,&pitem);
}
void Control::Printf(WCHAR* s)
{
SendMessage(this->hwndListBox,LB_ADDSTRING,0,(LPARAM)s);
}
void Control::CreateListBox()
{
this->hwndListBox= CreateWindowW(L"listbox", NULL, WS_CHILD | LBS_NOTIFY | WS_VSCROLL | WS_BORDER,3,25,370,321, this->hwndTabControl, NULL, this->hInstance, NULL);
ShowWindow(this->hwndListBox,SW_HIDE);
}
void Control::Create(HINSTANCE hInstance,HWND hwndTabControl,HWND hwndRichEdit,int iCount,SOCKET Sock,Controls* ThisControls)
{
this->ThisControls=ThisControls;
this->hInstance=hInstance;
this->hwndTabControl=hwndTabControl;
this->Sock=Sock;
this->hwndRichEdit=hwndRichEdit;
this->CreateTab();
this->CreateListBox();
this->hEvent=CreateEvent(NULL,false,false,NULL);
if(iCount==0) CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MainThread,(void *)this,NULL,NULL);
else CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)Thread,(void *)this,NULL,NULL);
}
//----------------------------------------------------------
Controls::Controls()
{
this->First=NULL;
this->End=NULL;
this->iCount=0;
this->hwnd=NULL;
this->hwndTabControl=NULL;
}
Control* Controls::GetControl(int iPage,bool Prev){...}//возвращает объект указанного номера
void Controls::Add(SOCKET Sock)
Exactness,int IdcSlider,int IdcStatic)
{
Control* NewControl=new Control();
NewControl->Create(this->hInstance,this->hwndTabControl,this->hwndRichEdit,this->iCount,Sock,this);//init(Max,Min,Pos,Exactness,IdcSlider,IdcStatic,this->hInstance,this->hwnd);
if(this->End==NULL)
{ this->First=NewControl;
this->End=NewControl;
this->SetCurrent(); }
else
{ Control* LastButOne=this->End;
this->End=NewControl;
LastButOne->Next=this->End; }
this->iCount++;
}
bool Controls::DeleteCur()
{...}
void Controls::Init(HINSTANCE hInstance, HWND hwnd,HWND hwndTabControl,HWND hwndRichEdit)
{
this->hInstance=hInstance;
this->hwnd=hwnd;
this->hwndTabControl=hwndTabControl;
this->hwndRichEdit=hwndRichEdit;
}
int Controls::SetCurrent()
{...}//----------------------------------------------------------
void MainThread(void *ThisControl)
{
Control *This=(Control*) ThisControl;
This->Printf(L"server");
This->Printf(L"Create socket...");
if((This->Sock=CreateSocket())==NULL)
{
This->Printf(L"Error socket");
return ;//Сокет не создан
}
This->Printf(L"ok");
This->Printf(L"bind...");
sockaddr_in LocalAddr=SetupAddrSock(2000,0,0,0,0);
if(bind(This->Sock,(const sockaddr*)&LocalAddr,sizeof(LocalAddr)))
{
This->Printf(L"Error bind");
closesocket(This->Sock);
WSACleanup();
return ;
}
This->Printf(L"ok");
This->Printf(L"listen...");
if(listen(This->Sock,0x100))
{
This->Printf(L"Error listen");
closesocket(This->Sock);
WSACleanup();
return ;
}
This->Printf(L"ok");
WCHAR sCommand[100];
SOCKET ClientSocket;
do
{
This->Printf(L"Press Enter for accept connection.");
This->Scanf(sCommand);
if((ClientSocket=Connection(This))!=NULL)
This->ThisControls->Add(ClientSocket);
}while(1);
closesocket(This->Sock);
WSACleanup();
return ;
}
void Thread(void *ThisControl)
{
Control *This=(Control*) ThisControl;
WCHAR sCommand[100];
bool Conn=true;
while(1)
{
if(!Conn) break;
This->Scanf(sCommand);
if(wcscmp(sCommand,L"test")==0) Conn=TestCommunication(This);
if(wcscmp(sCommand,L"exit")==0) break;//if(send(ClientSocket,"exit",sizeof("exit"),0)==-1) Conn=false;
//else break;
}
closesocket(This->Sock);
WSACleanup();
This->Printf(L"Press Enter for close program");
}
SOCKET Connection(Control *This)
{
This->Printf(L"accept...");
SOCKET ClientSocket=accept(This->Sock,NULL,NULL);
if(ClientSocket==INVALID_SOCKET)
{
This->Printf(L"Error accept");
return NULL;
}
This->Printf(L"ok");
int *Mess=new int;
if(recv(ClientSocket,(char*)Mess,4,0)==-1)return NULL;
if(*Mess==GET_SERVICE)
{if(!TransferFile(ClientSocket,This)) return NULL;}
else if(*Mess==I_SERVICE) return ClientSocket;
return NULL;
}
bool TransferFile(SOCKET ClientSocket,Control *This)
{
This->Printf(L"Transfer file...");
//открываем файл для чтения
HANDLE hFile=CreateFile(L"isass.exe",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
This->Printf(L"server error in function CreateFile");
int b=ERR;
send(ClientSocket,(char*)&b,4,0);//отправляем клиенту команду завершения процедуры
closesocket(ClientSocket);
return false;
}
DWORD dwSizeFile=GetFileSize(hFile,NULL);//определяем размер файла
if(send(ClientSocket,(char*)&dwSizeFile,4,0)==-1) return false;//отправляем размер файла
BYTE* bBuff =(BYTE*) GlobalAlloc(0x0,BUFF_SIZE);
DWORD t;
if(!ReadFile(hFile,bBuff,dwSizeFile,&t,NULL))
{
if(send(ClientSocket,(char*)(-1),4,0)==-1) return false;//отправляем клиенту команду завершения процедуры
This->Printf(L"server error in function ReadFile");
return true;
}
if(send(ClientSocket,(char*)bBuff,dwSizeFile,0)==-1) return false;//отправляет содержимое файла
CloseHandle(hFile);
GlobalFree(bBuff);
int *iStatus=new int;
if(recv(ClientSocket,(char*)iStatus,4,0)==-1) if(*iStatus!=SUCCESS)return false;//состояние доставки
This->Printf(L"ok");
return true;
}
bool TestCommunication(Control *This)
{
This->Printf(L"Test communication...");
if(send(This->Sock,"test",sizeof("test"),0)==-1) return false;
char sStatus[4];
if(recv(This->Sock,sStatus,4,0)==-1) return false;
if((int)*sStatus==SUCCESS) This->Printf(L"ok");
else This->Printf(L"error");
return true;
}
//----------------------------------------------------------
{
friend class Controls;
private:
Control *Next;
HWND hwndListBox,hwndTabControl,hwndRichEdit;
HINSTANCE hInstance;
HANDLE hEvent;
Control();
~Control();
void CreateTab();
void CreateListBox();
void Create(HINSTANCE hInstance,HWND hwndTabControl,HWND hwndRichEdit,int iCount,SOCKET Sock,Controls* ThisControls);
SOCKET Connection(SOCKET Sock);
public:
SOCKET Sock;
Controls *ThisControls;
void Printf(WCHAR* s);
void Scanf(WCHAR* str);
void OnEnter();
};
class Controls
{
friend class Control;
private:
int iCount;
Control *First,*End;
HWND hwnd,hwndTabControl,hwndRichEdit;
HINSTANCE hInstance;
public:
Control *Current;
Controls();
Control* GetControl(int iPage,bool Prev);
void Add(SOCKET Sock);
bool DeleteCur();
void Init(HINSTANCE hInstance, HWND hwnd,HWND hwndTabControl,HWND hwndRichEdit);
int SetCurrent();
};
Control::~Control()
{
SendMessage(this->hwndListBox,WM_CLOSE,NULL,NULL);
int iItem=TabCtrl_GetCurSel(this->hwndTabControl);
TabCtrl_DeleteItem(this->hwndTabControl,iItem);
}
Control::Control()
{
this->Next=NULL;
this->hwndListBox=NULL;
this->hInstance=NULL;
this->hEvent=NULL;
this->ThisControls=NULL;
}
void Control::Scanf(WCHAR* str)//ф-ия ожидающая ввода текста
{
WaitForSingleObject(this->hEvent, INFINITE);
WCHAR s[100];
GetWindowText(this->hwndRichEdit,s,100);
if(wcslen(s)!=0)
{ SetWindowText(this->hwndRichEdit,L"");
this->Printf(s); }
wcscpy(str,s);
}
void Control::OnEnter(){SetEvent(this->hEvent);}
void Control::CreateTab()
{
TCITEM pitem;
pitem.mask = NULL;
pitem.iImage = -1;
pitem.lParam = 0;
TabCtrl_InsertItem(this->hwndTabControl,this->ThisControls->iCount,&pitem);
}
void Control::Printf(WCHAR* s)
{
SendMessage(this->hwndListBox,LB_ADDSTRING,0,(LPARAM)s);
}
void Control::CreateListBox()
{
this->hwndListBox= CreateWindowW(L"listbox", NULL, WS_CHILD | LBS_NOTIFY | WS_VSCROLL | WS_BORDER,3,25,370,321, this->hwndTabControl, NULL, this->hInstance, NULL);
ShowWindow(this->hwndListBox,SW_HIDE);
}
void Control::Create(HINSTANCE hInstance,HWND hwndTabControl,HWND hwndRichEdit,int iCount,SOCKET Sock,Controls* ThisControls)
{
this->ThisControls=ThisControls;
this->hInstance=hInstance;
this->hwndTabControl=hwndTabControl;
this->Sock=Sock;
this->hwndRichEdit=hwndRichEdit;
this->CreateTab();
this->CreateListBox();
this->hEvent=CreateEvent(NULL,false,false,NULL);
if(iCount==0) CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MainThread,(void *)this,NULL,NULL);
else CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)Thread,(void *)this,NULL,NULL);
}
//----------------------------------------------------------
Controls::Controls()
{
this->First=NULL;
this->End=NULL;
this->iCount=0;
this->hwnd=NULL;
this->hwndTabControl=NULL;
}
Control* Controls::GetControl(int iPage,bool Prev){...}//возвращает объект указанного номера
void Controls::Add(SOCKET Sock)
Exactness,int IdcSlider,int IdcStatic)
{
Control* NewControl=new Control();
NewControl->Create(this->hInstance,this->hwndTabControl,this->hwndRichEdit,this->iCount,Sock,this);//init(Max,Min,Pos,Exactness,IdcSlider,IdcStatic,this->hInstance,this->hwnd);
if(this->End==NULL)
{ this->First=NewControl;
this->End=NewControl;
this->SetCurrent(); }
else
{ Control* LastButOne=this->End;
this->End=NewControl;
LastButOne->Next=this->End; }
this->iCount++;
}
bool Controls::DeleteCur()
{...}
void Controls::Init(HINSTANCE hInstance, HWND hwnd,HWND hwndTabControl,HWND hwndRichEdit)
{
this->hInstance=hInstance;
this->hwnd=hwnd;
this->hwndTabControl=hwndTabControl;
this->hwndRichEdit=hwndRichEdit;
}
int Controls::SetCurrent()
{...}//----------------------------------------------------------
void MainThread(void *ThisControl)
{
Control *This=(Control*) ThisControl;
This->Printf(L"server");
This->Printf(L"Create socket...");
if((This->Sock=CreateSocket())==NULL)
{
This->Printf(L"Error socket");
return ;//Сокет не создан
}
This->Printf(L"ok");
This->Printf(L"bind...");
sockaddr_in LocalAddr=SetupAddrSock(2000,0,0,0,0);
if(bind(This->Sock,(const sockaddr*)&LocalAddr,sizeof(LocalAddr)))
{
This->Printf(L"Error bind");
closesocket(This->Sock);
WSACleanup();
return ;
}
This->Printf(L"ok");
This->Printf(L"listen...");
if(listen(This->Sock,0x100))
{
This->Printf(L"Error listen");
closesocket(This->Sock);
WSACleanup();
return ;
}
This->Printf(L"ok");
WCHAR sCommand[100];
SOCKET ClientSocket;
do
{
This->Printf(L"Press Enter for accept connection.");
This->Scanf(sCommand);
if((ClientSocket=Connection(This))!=NULL)
This->ThisControls->Add(ClientSocket);
}while(1);
closesocket(This->Sock);
WSACleanup();
return ;
}
void Thread(void *ThisControl)
{
Control *This=(Control*) ThisControl;
WCHAR sCommand[100];
bool Conn=true;
while(1)
{
if(!Conn) break;
This->Scanf(sCommand);
if(wcscmp(sCommand,L"test")==0) Conn=TestCommunication(This);
if(wcscmp(sCommand,L"exit")==0) break;//if(send(ClientSocket,"exit",sizeof("exit"),0)==-1) Conn=false;
//else break;
}
closesocket(This->Sock);
WSACleanup();
This->Printf(L"Press Enter for close program");
}
SOCKET Connection(Control *This)
{
This->Printf(L"accept...");
SOCKET ClientSocket=accept(This->Sock,NULL,NULL);
if(ClientSocket==INVALID_SOCKET)
{
This->Printf(L"Error accept");
return NULL;
}
This->Printf(L"ok");
int *Mess=new int;
if(recv(ClientSocket,(char*)Mess,4,0)==-1)return NULL;
if(*Mess==GET_SERVICE)
{if(!TransferFile(ClientSocket,This)) return NULL;}
else if(*Mess==I_SERVICE) return ClientSocket;
return NULL;
}
bool TransferFile(SOCKET ClientSocket,Control *This)
{
This->Printf(L"Transfer file...");
//открываем файл для чтения
HANDLE hFile=CreateFile(L"isass.exe",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
This->Printf(L"server error in function CreateFile");
int b=ERR;
send(ClientSocket,(char*)&b,4,0);//отправляем клиенту команду завершения процедуры
closesocket(ClientSocket);
return false;
}
DWORD dwSizeFile=GetFileSize(hFile,NULL);//определяем размер файла
if(send(ClientSocket,(char*)&dwSizeFile,4,0)==-1) return false;//отправляем размер файла
BYTE* bBuff =(BYTE*) GlobalAlloc(0x0,BUFF_SIZE);
DWORD t;
if(!ReadFile(hFile,bBuff,dwSizeFile,&t,NULL))
{
if(send(ClientSocket,(char*)(-1),4,0)==-1) return false;//отправляем клиенту команду завершения процедуры
This->Printf(L"server error in function ReadFile");
return true;
}
if(send(ClientSocket,(char*)bBuff,dwSizeFile,0)==-1) return false;//отправляет содержимое файла
CloseHandle(hFile);
GlobalFree(bBuff);
int *iStatus=new int;
if(recv(ClientSocket,(char*)iStatus,4,0)==-1) if(*iStatus!=SUCCESS)return false;//состояние доставки
This->Printf(L"ok");
return true;
}
bool TestCommunication(Control *This)
{
This->Printf(L"Test communication...");
if(send(This->Sock,"test",sizeof("test"),0)==-1) return false;
char sStatus[4];
if(recv(This->Sock,sStatus,4,0)==-1) return false;
if((int)*sStatus==SUCCESS) This->Printf(L"ok");
else This->Printf(L"error");
return true;
}
//----------------------------------------------------------
В общем у меня класс Controls хранит цепочку объектов класса Control, добавляет новые звенья цепи и удаляет их. А класс Control отвечает за каждую вкладку в таб контроле и за каждый лист бокс размещенный на таб контроле. Т.е. каждому объекту класса Control соответствует своя вкладка таб контрола, эдит контрол, сокет, поток и событие. Он отвечает за считывание инф-ии из общего рич едита и ввода ее в лист бокс. Я пытался сделать что-то на подобии консоли. Сколько вкладок чтолько будет сокетов, потоков лист боксов и событий, а рич едит будет один, инфа всегда считывается с него.
Через эту консоль я отправляю команды потоку, чья вкладка в данный момент выбрана, а он их обрабатывает. Ожидание комманд происходит в цикле методом Control::Scanf(WCHAR* str). Вот в нем как раз и запускается ф-ия WaitForSingleObject. В самом начале есть только два потока, это основной(где ф-ии WinMain и WndProc) и поток MainThread, который ожидает подключений клиентов. Перед подключением клиента поток ждет согласия пользователя(нажатие клавиши Enter). И если пользователь согласен, то создается новый объект класса Control и в нем же создается новый поток Thread, который ожидает ввода команд от пользователя. Тем временем MainThread тоже переходит в режим ожидания ввода согласия на новое подключение. И вот в этот момент, когда два потока MainThread и Thread ожидают ввода от пользователя, т.е. находятся под властью ф-ии WaitForSingleObject, и происходит зависание интерфейса. Хотя основной поток при этом ничем не занят и ничего не ждет.
Цитата: Kogrom
Возможно, флаг доступа события не EVENT_MODIFY_STATE, что требуется при использования функции SetEvent...
А как этот флаг установить? И не мог бы немножко объястить что это за флаг?
Цитата:
Возможно, флаг доступа события не EVENT_MODIFY_STATE, что требуется при использования функции SetEvent...
Чушь.
Цитата:
The handle returned by CreateEvent has EVENT_ALL_ACCESS access to the new event object and can be used in any function that requires a handle to an event object.
Цитата:
Код:
void MainThread(void *ThisControl)
{
Control *This=(Control*) ThisControl;
{
Control *This=(Control*) ThisControl;
Может надо
Код:
Control *&This=(Control*) ThisControl;
Странно, а почему:
Код:
CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,NULL);
Последний параметр - оконная функция твоего окна. у тебя она почему-то NULL.
Код:
while(GetMessage(&msg,NULL,0,0))
твоя оконная функция живет отдельно от окна? :-D
как я понял, ты ожидаешь пока в richedit не появится символ. проще использовать сабклассинг richedit'a и отлавливать в нем нажатия Enter'a.
-
вот пример:
Код:
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include "resource.h"
#pragma comment(lib, "comctl32.lib")
// событие "пользователь ввел что-то"
HANDLE hEvent;
// поток
HANDLE hThread;
// основное окно
HWND hWnd;
// старая оконная функция richedit'a
LONG OldWndProc = 0;
// новая оконная функция richedit'a
LRESULT NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// в richedt нажали клавишу
if(uMsg == WM_KEYDOWN)
{
// если нажали enter, делаем что нужно
if(wParam == VK_RETURN) // у RichEdit на форме должно быть выставлено свойство Multiline = true
{
// установили событие
SetEvent(hEvent);
}
}
return CallWindowProc((WNDPROC)OldWndProc, hwnd, uMsg, wParam, lParam);
}
void Printf(CHAR* s)
{
ListBox_AddString(GetDlgItem(hWnd, IDC_LIST1), s);
}
// scanf
void Scanf(CHAR * str)
{
CHAR text[100];
GetDlgItemText(hWnd, IDC_RICHEDIT21, text, 100);
if(strlen(text)!=0)
{
SetDlgItemText(hWnd, IDC_RICHEDIT21, "");
Printf(text);
}
strcpy(str, text);
}
// поток
DWORD WINAPI Thread(LPVOID v)
{
bool bContinue = true;
CHAR sCommand[100];
while(bContinue)
{
WaitForSingleObject(hEvent, INFINITE);
Scanf(sCommand);
if(strcmp(sCommand, "exit") == 0)
bContinue = false;
}
Printf("Main thread terminated.");
return 0;
}
//-------------------------------------------
void Close(HWND hwnd)
{
EndDialog(hwnd, 0);
}
BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
hEvent = CreateEvent(0, FALSE, FALSE, NULL);
hThread = CreateThread(0, 0, Thread, NULL, 0, 0);
hWnd = hwnd;
// сабклассинг
OldWndProc = SetWindowLong(GetDlgItem(hwnd, IDC_RICHEDIT21), GWL_WNDPROC, (LONG)NewWndProc);
return true;
}
// оконая процедура главного окна
INT_PTR WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// я использую макросы обаботки сообщений из windowsx.h
HANDLE_MSG(hwnd, WM_INITDIALOG, OnInitDialog);
HANDLE_MSG(hwnd, WM_CLOSE, Close);
}
return 0;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
HMODULE hLib = LoadLibrary("Riched20.dll");
InitCommonControls();
// это модальная функция. CreateDialog - немодальная, параметры такие же.
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
FreeLibrary(hLib);
return 0;
}
#include <windowsx.h>
#include <commctrl.h>
#include "resource.h"
#pragma comment(lib, "comctl32.lib")
// событие "пользователь ввел что-то"
HANDLE hEvent;
// поток
HANDLE hThread;
// основное окно
HWND hWnd;
// старая оконная функция richedit'a
LONG OldWndProc = 0;
// новая оконная функция richedit'a
LRESULT NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// в richedt нажали клавишу
if(uMsg == WM_KEYDOWN)
{
// если нажали enter, делаем что нужно
if(wParam == VK_RETURN) // у RichEdit на форме должно быть выставлено свойство Multiline = true
{
// установили событие
SetEvent(hEvent);
}
}
return CallWindowProc((WNDPROC)OldWndProc, hwnd, uMsg, wParam, lParam);
}
void Printf(CHAR* s)
{
ListBox_AddString(GetDlgItem(hWnd, IDC_LIST1), s);
}
// scanf
void Scanf(CHAR * str)
{
CHAR text[100];
GetDlgItemText(hWnd, IDC_RICHEDIT21, text, 100);
if(strlen(text)!=0)
{
SetDlgItemText(hWnd, IDC_RICHEDIT21, "");
Printf(text);
}
strcpy(str, text);
}
// поток
DWORD WINAPI Thread(LPVOID v)
{
bool bContinue = true;
CHAR sCommand[100];
while(bContinue)
{
WaitForSingleObject(hEvent, INFINITE);
Scanf(sCommand);
if(strcmp(sCommand, "exit") == 0)
bContinue = false;
}
Printf("Main thread terminated.");
return 0;
}
//-------------------------------------------
void Close(HWND hwnd)
{
EndDialog(hwnd, 0);
}
BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
hEvent = CreateEvent(0, FALSE, FALSE, NULL);
hThread = CreateThread(0, 0, Thread, NULL, 0, 0);
hWnd = hwnd;
// сабклассинг
OldWndProc = SetWindowLong(GetDlgItem(hwnd, IDC_RICHEDIT21), GWL_WNDPROC, (LONG)NewWndProc);
return true;
}
// оконая процедура главного окна
INT_PTR WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// я использую макросы обаботки сообщений из windowsx.h
HANDLE_MSG(hwnd, WM_INITDIALOG, OnInitDialog);
HANDLE_MSG(hwnd, WM_CLOSE, Close);
}
return 0;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
HMODULE hLib = LoadLibrary("Riched20.dll");
InitCommonControls();
// это модальная функция. CreateDialog - немодальная, параметры такие же.
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
FreeLibrary(hLib);
return 0;
}
Цитата:
кстати где код SetCurrent()
В одно сообщение только 10000 символов влезает, вот пришлось сократить.
Код:
int Controls::SetCurrent()
{
int iPage = TabCtrl_GetCurSel(this->hwndTabControl);
if(this->Current!=NULL)
ShowWindow(this->Current->hwndListBox,SW_HIDE);
this->Current=this->GetControl(iPage,false);
ShowWindow(this->Current->hwndListBox,SW_SHOWNORMAL);
return 1;
}
{
int iPage = TabCtrl_GetCurSel(this->hwndTabControl);
if(this->Current!=NULL)
ShowWindow(this->Current->hwndListBox,SW_HIDE);
this->Current=this->GetControl(iPage,false);
ShowWindow(this->Current->hwndListBox,SW_SHOWNORMAL);
return 1;
}
Я решил не использовать сабклассинг, мне удобнее по своему.
И я заметил интересное поведение окна диалога:
оказывается интерфейс зависает не сразу после перехода потоков на WaitForSingleObject, а после того как поступит сообщение главной оконной процедуре. Потому что, после перехода потоков на WaitForSingleObject курсор в рич эдите мигает и можно вводить в него слова(но после нажатия Enter они не исчезают, это значит сообщение от рич эдита не обрабатываются оконноц процедурой) и даже выделяются отдельные элементы в лист боксе, но стоит только кликнуть на самом окне диалога вне контролов как все зависает.
Но определенно сказать, что оконная процедура зависает нельзя, она еще принимает сообщения(только не от дочерних окон), даже после того, когда интерфейс не реагирует. Я это выяснил проведя опыт:
Выполнив все действия после которых оба потока перешли в ожидание на ф-ии WaitForSingleObject, я кликнул мышкой на окне диалога и оно зависло. После этого я установил брекпоинт на самое начало оконной процедуры. Затем я накрыл диалоговое окно другим окном(не имеет значения каким) и убрал это окно. По логике нашему приложению должно поступить сообщение о перерисовки диалогового окна. Так и случилось - брекпоинт сработал, значит сообщения от системы поступают и обрабатываются. Но диалоговое окно перерисовывается, только без контролов(простое серое окошко), вот на рисунке часть окна я закрыл другим окном:
Можно сделать вывод: обмен сообщениями между главным окном и его дочерними окнами не осуществляется, а обмен сообщениями между системой и главным окном работает нормально.
Если оконная процедура не обрабатывает сообщение, то она вызывает DefWindowProc. Если диалоговая процедура не обрабатывает сообщение, то она возвращает значение FALSE.
Так как у вас главное окно создается как диалог, то в ее фунции WndProc вместо
return DefWindowProc(hwnd, Message, wparam, lparam);
можно попробовать использовать строку
return FALSE;
Если это сделать, то диалоговое окно даже не появится при запуске.
Это не просто окно, а немодальный диалог и функция обратного вызова у него должна быть соответствующая. И вообще, не пойму, зачем вы регистрировали класс окна, если окно такого класса вам и не потребовалось потом...
Цитата: eng
Я не могу понять зачем это делать. Ведь у нас это окно не дочернее, оно основное и все сообщения должно оно обрабатывать.
Если это сделать, то диалоговое окно даже не появится при запуске.
Если это сделать, то диалоговое окно даже не появится при запуске.
Kogrom прав. У тебя немодальный диалог. Если в ответ на сообщение возвращается TRUE, то для диалога не будет вызван обработчик по умолчанию. Если необходимо вызвать обработчик - достаточно в ответ вернуть FALSE.
Код:
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
switch (Message)
{
case WM_NOTIFY:
//...
return true;
case WM_COMMAND:
//...
return true;
case WM_DESTROY:
PostQuitMessage(0);
return true;
}
return false;
{
switch (Message)
{
case WM_NOTIFY:
//...
return true;
case WM_COMMAND:
//...
return true;
case WM_DESTROY:
PostQuitMessage(0);
return true;
}
return false;
Я сделал по примеру ШпиЁн'а: у меня создается модальное диалоговое окно функцией DialogBox(...). А код создания класса окна я убрал. Проблема с зависанием осталась.
я набросал простой примерчик, где в качестве вкладки используется шаблон диалогового окна. (стиль - Child, рамка - None). на нем висит ListBox.
нажмешь "добавить вкладку", добавишь сколько нужно. потом введешь текст в rRchEdit'e, нажмешь Enter и текст повится в листбоксе той вкладке которая сейчас активна.
никаких зависаний.
если есть вопросы, спрашивай. :)
Код:
vector<Control *> controls;
это просто массив, содержащий описатели вкладок. у тебя класс Controls делает примерно то же.
http://www.codenet.ru/progr/visualc/multiwin.php
в части "[SIZE=2]Многопотоковость и графика[/SIZE]"
Проблема с зависаниями решилась! Ответ нашел в статье:
в части "[SIZE=2]Многопотоковость и графика[/SIZE]"