2012-03-11 19 views
5

Tôi đã có một hàm:Tạo cửa sổ trong thread khác (không phải chủ đề chính)

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; 

} 

Và đây là phần chính của chương trình của tôi:

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; 

Khi tôi gọi hàm createMainWindow() trong phần chính của chương trình của tôi nó hoạt động như nó cần, nhưng khi tôi chạy nó trong chủ đề của tôi (ClientThread) nó không hoạt động. Tôi đã đọc rằng tôi nên tạo cửa sổ chỉ trong chủ đề chính. Có đúng không? Và nếu nó là sự thật, cách đơn giản nhất để gọi chức năng này từ một bước khác được thực hiện trong chủ đề chính là gì?


Cảm ơn mọi người. Bây giờ tôi biết vấn đề, nhưng tôi bị mắc kẹt với giải pháp. Mã chủ đề khách hàng của tôi là:

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; 

    } 

chức năng receiveMsgByUdp() dừng chuỗi này cho đến khi nhận được thông báo. Tôi xin lỗi vì thiếu kiến ​​thức, nhưng tôi có thể sử dụng những chức năng nào hoặc một công cụ khác để giải quyết vấn đề này. Tôi có nên viết lại phương thức getMsgByUdp() của tôi để không đồng bộ hoặc làm thế nào tôi có thể gọi hàm createMainWindow() để chạy trên thread chính? Về biến thể cuối cùng: làm thế nào tôi có thể làm điều này trong winapi thuần túy, tôi không thể tìm thấy bất kỳ ví dụ đơn giản nào. Ai đó có thể cung cấp đoạn mã. Cảm ơn thêm một lần nữa)

+0

Cảm ơn mọi người.Tôi đã cố gắng làm cho chương trình này hoạt động. tôi đã sử dụng phương pháp của David Heffernan. Và thông tin về liên kết này http://stackoverflow.com/questions/7060686/how-do-i-sendmessage-to-a-window-created-on-another-thread – knightOfSpring

Trả lời

6

Bạn thực sự có thể tạo cửa sổ trong các chủ đề khác với chuỗi giao diện người dùng chính. Tuy nhiên, các cửa sổ đó sẽ có ái lực với chuỗi tạo ra chúng và bạn sẽ cần phải chạy một máy bơm tin nhắn trong mỗi và mọi luồng tạo ra các cửa sổ.

Vì vậy, trong khi bạn có thể làm những gì bạn yêu cầu, Win32 thực sự được thiết kế để làm việc với tất cả các cửa sổ trong một quy trình có ái lực với cùng một chuỗi. Có thực sự không có gì để đạt được từ việc tạo ra nhiều chủ đề giao diện người dùng. Tất cả những gì bạn sẽ thành công khi làm là làm cho cuộc sống của bạn trở nên vô cùng phức tạp và không cần thiết phức tạp.

+0

Vâng, nó phức tạp. Nhưng trong tình huống của tôi, tôi không thể tìm thấy một giải pháp khác. Trong ổ cắm thread không chính nhận được tin nhắn, và khi tôi nhận được messsage đặc biệt tôi cần phải tạo ra cửa sổ. Tôi không biết làm thế nào để tạo ra nó trong chủ đề chính. Tôi là người mới trong winapi, vì vậy có lẽ bạn sẽ cho tôi biết làm thế nào để quản lý để làm loại lừa? – knightOfSpring

+0

Đây là một tình huống phổ biến. Những gì bạn làm là gửi hoặc gửi tin nhắn đến chủ đề chính và nhận chủ đề chính để tạo cửa sổ. Tất cả các khung công tác GUI đều cung cấp các cơ chế để hỗ trợ kịch bản này. –

+0

Nhưng nếu tôi cần phải làm điều này trong winapi tinh khiết? Nó sẽ rất phức tạp? – knightOfSpring

3

Bạn có thể tạo cửa sổ theo chủ đề "không chính" nhưng lưu ý rằng các cửa sổ đó được gắn vào chuỗi tạo và bạn cần đảm bảo triển khai vòng lặp thư ở đó và tiếp tục gửi tin nhắn đã đăng trên hàng đợi. Nếu bạn không làm điều này, cửa sổ của bạn sẽ đóng băng.

Xem:

Hệ thống không tự động tạo một hàng đợi thông điệp cho mỗi thread . Thay vào đó, hệ thống chỉ tạo hàng đợi thư cho các chủ đề thực hiện các thao tác yêu cầu hàng đợi thư. Nếu chủ đề tạo một hoặc nhiều cửa sổ, một vòng lặp tin nhắn phải được cung cấp; vòng lặp tin nhắn này truy xuất thư từ hàng đợi thư của chuỗi và gửi chúng đến các thủ tục cửa sổ thích hợp.

+0

Vì vậy, tất cả những gì tôi cần làm là thêm mã vào chuỗi không chính của tôi để gửi thư. Nhưng có một vấn đề: trong thread này tôi làm việc với ổ cắm, tôi nhận được tin nhắn, và một số chức năng dừng vòng lặp của tôi cho đến khi socket nhận được tin nhắn. Tôi nghĩ cách duy nhất để giải quyết vấn đề này là tạo một luồng khác trong chuỗi không chính của tôi để phân phát thư từ cửa sổ. Bạn nghĩ sao? – knightOfSpring

+0

@Roman Theo quan điểm của tôi, sẽ là một lời khuyên xấu khi đề xuất rằng nhiều chuỗi giao diện người dùng là giải pháp tốt nhất ở đây. Ý kiến ​​của bạn là gì? Bạn có đồng ý với tôi hay không? –

+0

Bạn có các lựa chọn cho API để làm việc với các ổ cắm, tất cả những gì bạn cần không phải là tránh các cuộc gọi chặn trong đó việc thực hiện đang mất nhiều thời gian trong API. –

3

Nếu bạn tạo cửa sổ trong chuỗi khác, bạn cũng sẽ cần triển khai vòng lặp thư trên chuỗi đó vì các thư được xếp hàng đợi được đăng lên hàng đợi thư của chuỗi sở hữu cửa sổ.

Các vấn đề liên quan