2012-03-11 3 views
5

У меня есть функция:окно Создание в другом потоке (не основной поток)

HWND createMainWindow(P2p_Socket_Machine * toSend){ 

    HWND hMainWnd = CreateWindow( 
     L"Class",/*(LPCWSTR) nameOfConference.c_str()*/L"Chat", WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU, 
    CW_USEDEFAULT, 0, 600,400, 
    (HWND)NULL, (HMENU)NULL, 
    /*(HINSTANCE)hlnstance*/NULL, NULL 
    ); 

    if (!hMainWnd) { 
     MessageBox(NULL, L"Cannot create main window", L"Error", MB_OK); 
     return 0; 
    } 

    CreateWindowA("LISTBOX",NULL, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|LBS_NOTIFY|LBS_MULTIPLESEL,310,30,255,275,hMainWnd,(HMENU)List_Box,NULL,NULL); 

    CreateWindowExA(NULL,"BUTTON", "Refresh", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,385,310,100,24,hMainWnd,(HMENU)Button_Refresh, NULL ,NULL); 

    CreateWindowExA(NULL,"BUTTON", "Send", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,385,334,100,24,hMainWnd,(HMENU)Button_Send, NULL ,NULL); 

    CreateWindowExA(NULL,"BUTTON", "New", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,385,354,100,24,hMainWnd,(HMENU)Button_New, NULL ,NULL); 

    CreateWindowA("EDIT",0,WS_BORDER|WS_VISIBLE|WS_CHILD|ES_LEFT|ES_MULTILINE|WS_VSCROLL|WS_DISABLED, 
    10,30,265,275,hMainWnd,(HMENU)Text_Box_Get,NULL,NULL); 

    CreateWindowA("EDIT",0,WS_BORDER|WS_VISIBLE|WS_CHILD|ES_LEFT|ES_MULTILINE|WS_VSCROLL, 
    10,320,265,45,hMainWnd,(HMENU)Text_Box_Send,NULL,NULL); 

    SetWindowLongPtr(hMainWnd,GWLP_USERDATA,(LONG_PTR)toSend); 

    ShowWindow(hMainWnd, SW_SHOW); 
    //UpdateWindow(hMainWnd); 

    return hMainWnd; 

} 

И это основная часть моей программы:

int WINAPI WinMain(HINSTANCE hlnstance, HINSTANCE hPrevInstance, LPSTR IpCmdLine, int 
nCmdShow) 
{ 
WNDCLASSEX wc; 
    wc.cbSize = sizeof(wc); 
    wc.style = CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc = MyFunc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hlnstance; 
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = L"Class"; 
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 
HWND toSend = createMainWindow(P2pSocket); 

//some code 

hThread = CreateThread(NULL, 0, ClientThread, 
      Message2, 0, &dwThreadId); 

     if (hThread == NULL) 
     { 
      cout<<"Create thread filed"; 
      exit(10); 
     } 


    while (GetMessage(&msg, NULL, 0, 0)) { 

     TranslateMessage(&msg); 
     DispatchMessage(&msg); 

    } 

    return msg.wParam; 

Когда я вызвать функцию createMainWindow() в основной части моей программы он работает так, как должен, но когда я запустил его в , мой поток (ClientThread) не работает. Я читал, что я должен создавать окна только в основном потоке. Это правда? И если это правда, какой самый простой способ вызвать эту функцию из другого ада, который нужно сделать в основном потоке?


Спасибо всем. Теперь я знаю проблему, но я застрял в решении. Мой код клиента нарезка:

while(1){ 

    vector<HWND> AllHandlers; 

    pair<string,string> Answer = Pointer->receiveMsgByUdp(); 

    if(!Pointer->isMyLocalAddress(Answer.first)){ 

     int type = messageUdpContentType(Answer.second); 

     switch(type){ 

     case 0 : 

      Pointer->sendMsgToIpUdp(Answer.first,"<?xml version='1.0'?><accepted/>"); 
      AllHandlers = getAllHandlersOfElementsOnWindowsByIdentityCode(Pointer->getAllHandlers(),List_Box); 
      for(vector<HWND>::iterator j = AllHandlers.begin();j!=AllHandlers.end();j++) 
       if(SendMessageA(*j, LB_FINDSTRINGEXACT, 0, (LPARAM)Answer.first.c_str())==LB_ERR) 
        SendMessageA(*j, LB_ADDSTRING, 0, (LPARAM)Answer.first.c_str()); 

      break; 

     case 1 : 
      AllHandlers = getAllHandlersOfElementsOnWindowsByIdentityCode(Pointer->getAllHandlers(),List_Box); 
      for(vector<HWND>::iterator j = AllHandlers.begin();j!=AllHandlers.end();j++) 
       if(SendMessageA(*j, LB_FINDSTRINGEXACT, 0, (LPARAM)Answer.first.c_str())==LB_ERR) 
        SendMessageA(*j, LB_ADDSTRING, 0, (LPARAM)Answer.first.c_str()); 

      break; 

     case 2 : 
      AllHandlers = getAllHandlersOfElementsOnWindowsByIdentityCode(Pointer->getAllHandlers(),List_Box); 
      for(vector<HWND>::iterator j = AllHandlers.begin();j!=AllHandlers.end();j++) 
       if((i = SendMessageA(*j, LB_FINDSTRINGEXACT, 0, (LPARAM)Answer.first.c_str()))!=LB_ERR) 
        SendMessageA(*j,LB_DELETESTRING, 0, (LPARAM)Answer.first.c_str()); 

      break; 

     case 3 : 

      userReply = MessageBoxW(NULL, L"Принять приглашение на конференцию?", 
        L"", MB_YESNO | MB_ICONQUESTION); 
      if (userReply==IDYES){ 

       //todo: Проверка на создание встречи, в которой уже состоишь 
       string nameOfConf = fetchNameOfInviteConf(Answer.second); 
       Pointer->createConference(nameOfConf); 
       HWND toSendTo = createMainWindow(Pointer); 
       Pointer->setHandlerInfo(nameOfConf,toSendTo);    
       Pointer->addNewMemberToConference_ServerType(nameOfConf,Answer.first); 
       string toSend = string("<?xml version='1.0'?><inviteAccepted>") + nameOfConf + string("</inviteAccepted>"); 
       Pointer->sendMsgToIpUdp(Answer.first,toSend); 

      } 
      break; 

     case 4 : 

      string nameOfConf = fetchNameOfInviteAcceptConf(Answer.second); 

      toSend.clear(); 
      Participants.clear(); 
      Participants = Pointer->getCurrentParticipants(nameOfConf); 
      toSend+="<?xml version='1.0'?>"; 
      toSend+="<conference>"; 
      toSend+="<nameOfConference>"; 
      toSend+=nameOfConf; 
      toSend+="</nameOfConference>"; 
      for(vector<string>::iterator i = Participants.begin();i!=Participants.end();i++){ 
       toSend+="<participant>" + *i + "</participant>"; 
      } 
      toSend+="</conference>"; 



      Pointer->addNewMemberToConference_ClientType(nameOfConf,Answer.first); 

      Pointer->sendToIpTcp(Answer.first,toSend); 

      break; 

    } 

функция receiveMsgByUdp() останавливает этот поток, пока не получит сообщение. Я извиняюсь из-за недостатка знаний, но какие функции я могу использовать или что-то еще, чтобы решить эту проблему. Должен ли я переписать мой метод receiveMsgByUdp() как асинхронный или как я могу вызвать функцию createMainWindow() для запуска в основном потоке? О последнем варианте: как я могу это сделать в чистом winapi, я не мог найти простых примеров. Может кто-нибудь дать фрагмент кода. Спасибо еще раз)

+0

Спасибо каждому.Мне удалось заставить эту программу работать. Я использовал метод Дэвид Хеффернан. И информация по этой ссылке http://stackoverflow.com/questions/7060686/how-do-i-sendmessage-to-a-window-created-on-another-thread – knightOfSpring

ответ

6

Вы действительно можете создавать окна в потоках, отличных от основного потока пользовательского интерфейса. Тем не менее, эти окна будут иметь отношение к потоку, который их создал, и вам нужно будет запустить насос сообщений в каждом потоке, который создает окна.

Итак, вы можете делать то, что вы просите, Win32 действительно предназначен для работы со всеми окнами в процессе, имеющем сходство с тем же потоком. От создания нескольких потоков пользовательского интерфейса нечего делать. Все, что вам удастся сделать, делает вашу жизнь необычайно и бесполезно сложной.

+0

Да, это сложно. Но в моей ситуации я не могу найти другого решения. В сообщениях, принимающих не связанные с основным потоком сообщения, и когда я получаю специальный messsage, мне нужно создать окно. Я не знаю, как создать его в основной теме. Я новичок в winapi, так что, может быть, вы скажете мне, как это сделать? – knightOfSpring

+0

Это распространенный сценарий. Что вы делаете, так это отправить или отправить сообщение в основной поток и получить основной поток для создания окна. Все рамки GUI предлагают механизмы поддержки этого сценария. –

+0

Но если мне нужно сделать это в чистом winapi? Будет ли это очень сложно? – knightOfSpring

3

Вы можете создавать окна на «не главных» потоках, но имейте в виду, что эти окна прикреплены к потоку создания, и вам нужно убедиться в том, что там будет реализован цикл сообщений и размещены отправленные сообщения в очереди. Если вы этого не сделаете, ваши окна будут заморожены.

См:

Система автоматически не создает очереди сообщений для каждого потока. Вместо этого система создает очередь сообщений только для потоков , которые выполняют операции, требующие очереди сообщений. Если поток создает одно или несколько окон, должен быть предоставлен контур сообщения; этот цикл сообщений извлекает сообщения из очереди сообщений потока, а отправляет их соответствующим процедурам окна.

+0

Итак, все, что мне нужно сделать, это добавить код для моего не основного потока для отправки сообщений. Но есть одна проблема: в этом потоке я работаю с сокетами, получаю сообщения, а некоторые функции останавливают мой цикл до тех пор, пока сокет не получит сообщение. Я думаю, что единственный способ решить эту проблему - создать другой поток в моем основном потоке для отправки сообщений из окна. Как вы думаете? – knightOfSpring

+0

@Roman На мой взгляд, было бы неплохо советовать предположить, что несколько потоков пользовательского интерфейса являются лучшим решением здесь. Каково ваше мнение? Вы согласны со мной или нет? –

+0

У вас есть выбор API для работы с сокетами, все, что вам нужно, не исключает блокировки вызовов, когда выполнение тратит длительные периоды времени в API. –

3

Если вы создаете окно в другом потоке, вам также понадобится реализовать цикл сообщений в этом потоке, поскольку сообщения в очереди отправляются в очередь сообщений потока, которая владеет окном.

Смежные вопросы