2012-03-11 14 views
5

Mam funkcję:Tworzenie okna w innym wątku (nie główny wątek)

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; 

} 

I to jest główną częścią mojego programu:

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; 

gdy zgłoszę funkcja createMainWindow() w głównej części mojego programu działa tak, jak powinien, ale gdy uruchomię go w mój wątek (ClientThread) nie działa. Czytałem, że powinienem tworzyć okna tylko w głównym wątku. Czy to prawda? A jeśli to prawda, jaki jest najprostszy sposób wywoływania tej funkcji od innego theada w głównym wątku?


Dziękuję wszystkim. Teraz znam problem, ale utknąłem z rozwiązaniem. Mój klient kod wątku jest:

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 function() zatrzymuje ten wątek aż otrzyma wiadomość. Przepraszam za brak wiedzy, ale jakie funkcje mogę użyć lub inne rzeczy, aby to rozwiązać. Czy powinienem przepisać metodę receiveMsgByUdp() na asynchroniczną lub jak mogę wywołać funkcję createMainWindow() do uruchomienia w głównym wątku? O ostatnim wariancie: jak mogę to zrobić w czystej winapi, nie mogłem znaleźć żadnych prostych przykładów. Czy ktoś może podać fragment kodu? Jeszcze raz dziękuję)

+0

Dzięki wszystkim.Udało mi się uruchomić ten program. użyłem metody Davida Heffernana. I informacje na ten link http://stackoverflow.com/questions/7060686/how-do-i-sendmessage-to-a-window-created-on-another-thread – knightOfSpring

Odpowiedz

6

Rzeczywiście, można tworzyć okna w wątkach innych niż główny wątek interfejsu użytkownika. Jednak te okna będą miały powinowactwo do wątku, który je utworzył i będziesz musiał uruchomić pompę komunikatów w każdym wątku, który tworzy okna.

Podczas gdy możesz zrobić to, o co poprosisz, Win32 jest naprawdę zaprojektowany do pracy ze wszystkimi oknami w procesie mającym powinowactwo do tego samego wątku. Naprawdę nic nie można zyskać, tworząc wiele wątków interfejsu użytkownika. Wszystko, co osiągniesz, to uczynić twoje życie wyjątkowo i niepotrzebnie skomplikowanym.

+0

Tak, to skomplikowane. Ale w mojej sytuacji nie mogę znaleźć innego rozwiązania. W głównym gnieździe wątku odbierane są wiadomości, a gdy otrzymuję specjalny komunikat, muszę utworzyć okno. Nie wiem, jak utworzyć go w głównym wątku. Jestem nowicjuszem w winapi, więc może powiesz mi, jak poradzić sobie z taką sztuczką? – knightOfSpring

+0

Jest to typowy scenariusz. Wystarczy wysłać lub wysłać wiadomość do głównego wątku i uzyskać główny wątek, aby utworzyć okno. Wszystkie ramy GUI oferują mechanizmy wspierające ten scenariusz. –

+0

Ale jeśli muszę to zrobić w czystym winapi? Czy będzie to bardzo skomplikowane? – knightOfSpring

3

Możesz tworzyć okna na wątkach "innych niż główne", ale pamiętaj, że te okna są dołączone do wątku tworzenia, i musisz upewnić się, że zaimplementujesz tam pętlę komunikatów i nadal wysyłasz wysłane wiadomości w kolejce. Jeśli tego nie zrobisz, twoje okna zamarzną.

Patrz:

System nie tworzy automatycznie kolejki wiadomości dla każdej wątku. Zamiast tego system tworzy kolejkę komunikatów tylko dla wątków , które wykonują operacje wymagające kolejki komunikatów. Jeśli wątek tworzy jedno lub więcej okien, należy podać pętlę komunikatów:; ta pętla komunikatów pobiera wiadomości z kolejki komunikatów wątku, a wysyła je do odpowiednich procedur okna.

+0

Wszystko, co muszę zrobić, to dodać kod do mojego nie-głównego wątku do wysyłania wiadomości. Ale jest jeden problem: w tym wątku pracuję z gniazdami, odbieram wiadomości, a niektóre funkcje zatrzymują moją pętlę, dopóki gniazdo nie otrzyma wiadomości. Myślę, że jedynym sposobem rozwiązania tego problemu jest utworzenie kolejnego wątku w moim nie-głównym wątku, który usunie wiadomości z okna. Co myślisz? – knightOfSpring

+0

@Roman Moim zdaniem byłoby złą radą sugerować, że wiele wątków interfejsu użytkownika jest tutaj najlepszym rozwiązaniem. Jaka jest Twoja opinia? Czy zgadzasz się ze mną, czy nie? –

+0

Masz do wyboru interfejs API do pracy z gniazdami, wszystko, czego potrzebujesz, to unikanie blokowania połączeń, w których wykonywanie trwa przez długi czas w interfejsie API. –

3

Jeśli utworzyć okno w innym wątku, będzie trzeba także realizować pętlę komunikatów na tym wątku, ponieważ w kolejce wiadomości są wysyłane do kolejki komunikatów nici która posiada okno.

Powiązane problemy