2012-03-11 20 views
5

tengo una función:ventana de Creación en otro hilo (no hilo principal)

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; 

} 

Y esto es parte principal de mi programa:

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; 

cuando llame a la función createMainWindow() en la parte principal de mi programa funciona como debería, pero cuando lo ejecuto en mi hilo (ClientThread) no funciona. He leído que debería crear ventanas solo en el hilo principal. ¿Es verdad? Y si es cierto, ¿cuál es la forma más sencilla de llamar a esta función desde otro lado para que se haga en el hilo principal?


Gracias a todos. Ahora sé el problema, pero estoy atascado con la solución. Mi código hilo de cliente es:

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; 

    } 

la receiveMsgByUdp función() deja este hilo hasta que recibe el mensaje. Me disculpo por la falta de conocimiento, pero qué funciones puedo usar u otras cosas para resolver esto. ¿Debería reescribir mi método receiveMsgByUdp() para que sea asíncrono o cómo puedo llamar a la función createMainWindow() para ejecutar en el hilo principal? Acerca de la última variante: cómo puedo hacer esto en winapi puro, no pude encontrar ningún ejemplo simple. ¿Alguien puede dar un fragmento de código? Gracias una vez más)

+0

Gracias a todos.Logré hacer que este programa funcione. utilicé el método de David Heffernan. Y la información en este enlace http://stackoverflow.com/questions/7060686/how-do-i-sendmessage-to-a-window-created-on-another-thread~~V~~singular~~3rd – knightOfSpring

Respuesta

6

De hecho, puede crear ventanas en hilos que no sean el hilo de la interfaz de usuario principal. Sin embargo, esas ventanas tendrán afinidad con el hilo que las creó y tendrá que ejecutar una bomba de mensajes en cada hilo que crea ventanas.

Si bien puede hacer lo que le pide, Win32 está realmente diseñado para funcionar con todas las ventanas en un proceso que tiene afinidad con el mismo hilo. No hay nada que ganar al crear múltiples hilos de UI. Todo lo que logrará es hacer que su vida sea extraordinaria e innecesariamente compleja.

+0

Sí, es complejo. Pero en mi situación no puedo encontrar otra solución. En el socket no principal, recibo mensajes, y cuando recibo un mensaje especial, necesito crear una ventana. No sé cómo crearlo en el hilo principal. Soy novato en winapi, ¿así que tal vez me diga cómo hacer este tipo de truco? – knightOfSpring

+0

Este es un escenario común. Lo que hace es enviar o publicar un mensaje en el hilo principal y obtener el hilo principal para crear la ventana. Todos los marcos de la GUI ofrecen mecanismos para respaldar este escenario. –

+0

¿Pero si necesito hacer esto en winapi puro? ¿Será muy complejo? – knightOfSpring

3

Puede crear ventanas en subprocesos "no principales", pero tenga en cuenta que esas ventanas están conectadas al subproceso de creación, y debe asegurarse de implementar un bucle de mensajes allí y seguir publicando mensajes en la cola Si no lo hace, sus ventanas se congelarán.

Ver:

El sistema no crea automáticamente una cola de mensajes para cada hilo. En cambio, el sistema crea una cola de mensajes solo para los hilos que realizan operaciones que requieren una cola de mensajes. Si el subproceso crea una o más ventanas, se debe proporcionar un ciclo de mensajes; este bucle de mensaje recupera los mensajes de la cola de mensajes del subproceso y los envía a los procedimientos de ventana apropiados.

+0

Por lo tanto, todo lo que tiene que hacer es añadir una codificar a mi hilo no principal para enviar mensajes. Pero hay un problema: en este hilo trabajo con conectores, recibo mensajes y algunas funciones detienen mi ciclo hasta que el socket recibe el mensaje. Creo que la única forma de resolver esto es crear otro hilo en mi hilo no principal para disparar mensajes desde la ventana. ¿Qué piensas? – knightOfSpring

+0

@Roman En mi opinión, sería un mal consejo sugerir que múltiples subprocesos de interfaz de usuario es la mejor solución aquí. ¿Cual es tu opinion? ¿Estás de acuerdo conmigo o no? –

+0

Tiene opciones para API para trabajar con sockets, todo lo que necesita es no evitar el bloqueo de llamadas donde la ejecución está pasando largos períodos de tiempo dentro de la API. –

3

Si crea una ventana en otro hilo, también deberá implementar un bucle de mensaje en ese hilo ya que los mensajes en cola se publican en la cola de mensajes del hilo que posee la ventana.

Cuestiones relacionadas