2012-03-11 96 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

感谢每一位。我设法让这个程序起作用。我使用了David Heffernan的方法。而这个环节上的信息http://stackoverflow.com/questions/7060686/how-do-i-sendmessage-to-a-window-created-on-another-thread – knightOfSpring 2012-03-11 15:53:36

回答

6

您确实可以创造比主UI线程其他线程的窗口。但是,这些窗口将与创建它们的线程相关联,并且您将需要在创建窗口的每个线程中运行消息泵。

因此,虽然你可以做你问什么,Win32的是真正设计的具有亲和力的同一线程进程中的所有窗口的工作。创建多个UI线程确实没有什么可以获得的。你所做的所有事情都会让你的生活变得异常复杂。

+0

是的,这很复杂。但在我的情况下,我找不到另一种解决方案。在非主线程套接字接收消息中,当我收到特殊消息时,我需要创建窗口。我不知道如何在主线程中创建它。我是winapi的新手,所以也许你会告诉我如何设法做这种伎俩? – knightOfSpring 2012-03-11 12:12:35

+0

这是一种常见的情况。你所做的是发送或发布消息到主线程并获得主线程来创建窗口。所有的GUI框架都提供了支持这种情况的机制。 – 2012-03-11 12:15:41

+0

但是,如果我需要在纯winapi中做到这一点?它会非常复杂吗? – knightOfSpring 2012-03-11 12:24:48

3

您可以在“非主要”线程上创建窗口,但请注意这些窗口已附加到创建线程,并且您需要确保在那里实现一个消息循环并保持发送消息发布在队列中。如果你不这样做,你的窗户将冻结。

参见:

系统不会自动创建用于每个 螺纹的消息队列。相反,系统仅为执行需要消息队列的操作的线程 创建消息队列。 如果线程 创建一个或多个窗口,则必须提供消息循环;这个 消息循环从线程的消息队列中检索消息并且将它们分派到适当的窗口过程。

+0

因此,所有我需要做的就是添加一个代码到我的非主线程来发送消息。但是有一个问题:在这个线程中,我使用套接字,我接收消息,并且一些函数阻止我的循环,直到套接字接收到消息。我认为解决这个问题的唯一方法是在我的非主线程中创建另一个线程来分散窗口中的消息。你怎么看? – knightOfSpring 2012-03-11 12:03:44

+0

@Roman在我看来,建议多个UI线程在这里是最好的解决方案将是不好的建议。你怎么看?你是否同意我的观点? – 2012-03-11 12:16:27

+0

您可以选择使用API​​来处理套接字,所有您需要的都是避免阻止执行在API中花费很长时间的调用。 – 2012-03-11 12:18:20

3

如果你在另一个线程创建一个窗口,你也将需要实现该线程的消息循环,因为排队的消息发布到线程的消息队列该公司拥有的窗口。

相关问题