Créer une fenêtre dans un autre fil (pas le fil principal)
-
11-12-2019 - |
Question
J'ai une fonction:
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;
}
Et c'est la partie principale de mon programme:
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;
Quand j'appelle la fonction CreatemainWindow () dans la partie principale de mon programme cela fonctionne comme il devrait, mais quand je l'exécute dans mon fil (clientthread) ça ne marche pas. J'ai lu que je devrais créer des fenêtres uniquement dans le fil principal. Est-ce vrai? Et si c'est vrai, quel est le moyen le plus simple d'appeler cette fonction d'une autre THEAD à faire dans le fil principal?
Merci tout le monde. Maintenant, je connais le problème, mais je suis coincé avec une solution. Mon code de thread de client est:
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 fonction reçue () arrête ce fil jusqu'à ce que reçoit un message. Je m'excuse pour le manque de connaissances, mais quelles fonctions puis-je utiliser ou une autre chose pour résoudre ce problème. Devrais-je réécrire ma méthode reçue () d'être asynchrone ou comment puis-je appeler la fonction CreatemainWindow () à exécuter sur le fil principal? À propos de la dernière variante: Comment puis-je le faire dans Pure Winapi, je n'ai pu trouver de simples exemples. Quelqu'un peut-il donner un extrait de code. Merci une fois de plus)
La solution
Vous pouvez en effet créer des fenêtres dans des threads autres que le fil UI principal.Cependant, ces fenêtres auront affini au fil qui les a créés et vous aurez besoin d'exécuter une pompe à un message dans chaque fil qui crée des fenêtres.
Alors, tandis que vous pouvez faire ce que vous demandez, Win32 est vraiment conçu pour fonctionner avec toutes les fenêtres dans un processus ayant une affinité au même fil.Il n'y a vraiment rien à gagner de la création de plusieurs fils d'interface utilisateur.Tout ce que vous réussirez à faire est de rendre votre vie extraordinairement et inutilement complexe.
Autres conseils
Vous pouvez créer des fenêtres de Windows sur des threads "non principaux", mais sachez que ces fenêtres sont attachées au fil de la création et que vous devez vous assurer de mettre en œuvre une boucle de message et de conserver des messages d'expédition affichés sur la file d'attente. Si vous ne faites pas cela, vos fenêtres vont geler.
Voir:
- Utilisation de messages et files d'attente de message
- Manipulation des messages - À propos des messages et files d'attente de message
Le système ne crée pas automatiquement une file d'attente de message pour chaque fil. Au lieu de cela, le système crée une file d'attente de message uniquement pour les fils. qui effectuent des opérations nécessitant une file d'attente de message.
si le fil Crée une ou plusieurs fenêtres, une boucle de message doit être fournie ; cette La boucle de message récupère les messages de la file d'attente de message du thread et les envoie aux procédures de fenêtre appropriées.
Si vous créez une fenêtre dans un autre thread, vous devez également implémenter une boucle de message sur ce fil puisque les messages en file d'attente sont affichés dans la file d'attente de message du fil qui possède la fenêtre.