Создание окна в другом потоке(не главном потоке)


У меня есть функция:

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) не работает. я читал, что я должен создавать окна только в главном потоке. Это правда? И если это правда, то каков самый простой способ вызвать эту функцию из другого thead, который должен быть выполнен в основном потоке?


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

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, я не смог найти никаких простых примеров. Может кто-нибудь дать код фрагмент. Спасибо еще раз)

3 5

3 ответа:

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

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

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

См.:

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

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