2009-11-18 10 views
1

Je travaille sur une couche de portabilité pour OpenGL (abstrait les trucs glX et wgl pour Linux et Windows) ... De toute façon, il y a une méthode pour créer une fenêtre ... Si vous ne passez pas dans un parent, vous obtenez une vraie fenêtre avec un cadre ... Si vous passez dans un parent, vous obtenez une fenêtre sans cadre, sans cadre ...L'appel Win32 CreateWindow() se bloque dans le thread enfant?

Cela fonctionne très bien, tant que je le fais tout sur 1 fil ... Dès qu'un autre thread tente de créer une fenêtre enfant, l'application se bloque dans l'appel win32 "CreateWindow()". Des idées?

Répondre

5

Ce n'est pas une vraie réponse, mais comme beaucoup de gens semblent croire que Win32 interdit de créer des enfants dans d'autres threads que le parent, je me sens obligé de poster une démonstration du contraire.

Le code ci-dessous illustre la création d'une fenêtre enfant sur un parent appartenant à un processus différent . Il accepte une valeur de handle de fenêtre en tant que paramètre de ligne de commande et crée une fenêtre enfant sur ce parent.

// t.cpp 

#include <windows.h> 
#include <stdio.h> 

#define CLASS_NAME L"fykshfksdafhafgsakr452" 


static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (msg) 
    { 
     case WM_DESTROY: 
      PostQuitMessage(0); 
      break; 

     case WM_PAINT: 
     { 
      PAINTSTRUCT ps; 
      BeginPaint(hwnd, &ps); 
      EndPaint(hwnd, &ps); 
      break; 
     } 
    } 
    return DefWindowProc(hwnd, msg, wParam, lParam); 
} 



int main(int argc, char* argv[]) 
{ 
    HWND parent = (argc >= 2) ? (HWND)strtoul(argv[1], 0, 0) : (HWND)0; 
    printf("parent: 0x%x\n", parent); 

    WNDCLASS wc = {}; 
    wc.lpfnWndProc = WindowProc; 
    wc.hInstance = (HINSTANCE)GetModuleHandle(NULL); 
    wc.lpszClassName = CLASS_NAME; 
    wc.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION + 1); 
    if (!RegisterClass(&wc)) 
    { 
     printf("%d: error %d\n", __LINE__, GetLastError()); 
     return 0; 
    } 

    const DWORD style = WS_CHILD | WS_VISIBLE; 

    HWND hwnd = CreateWindow(CLASS_NAME, L"Test", style, 50, 50, 100, 100, 
          parent, 0, wc.hInstance, 0); 

    if (!hwnd) 
    { 
     printf("%d: error %d\n", __LINE__, GetLastError()); 
     return 0; 
    } 

    MSG msg; 
    while (GetMessage(&msg, 0, 0, 0)) 
     DispatchMessage(&msg); 

    return 0; 
} 

compiler ce avec la commande suivante (en utilisant l'environnement de ligne de commande MSVC):

cl /EHsc /DUNICODE /D_UNICODE t.cpp user32.lib 

utiliser ensuite Spy ++ ou un autre outil pour obtenir la valeur de la poignée d'une fenêtre - par exemple, du Bloc-notes ou du navigateur sur lequel vous consultez ce site. Supposons que c'est 0x000. Ensuite, exécutez l'exemple compilé avec t.exe 0x1234. Utilisez Ctrl-C pour terminer t.exe (ou fermez simplement la fenêtre de la console).

-1

Une fenêtre est liée au thread qui le crée (plus précisément, à la file d'attente de messages de ce thread). Une fenêtre parent ne peut pas résider dans un thread différent de ses fenêtres enfants.

+0

Ce n'est pas ce que j'essaie de faire. Je veux que chaque thread prenne en charge SEULEMENT les fenêtres qu'il crée ... J'ai juste besoin de créer une fenêtre avec un parent créé par un autre thread ... – dicroce

+0

Cela ne fonctionnera PAS. Vous ne pouvez pas créer une fenêtre parent dans un thread, puis créer une fenêtre enfant dans un autre thread.Ils DOIVENT être dans le même fil. –

+0

Hmm ... Eh bien, je l'ai vraiment fait fonctionner ... Au fond, j'avais juste besoin de faire pomper le message des parents en pompant ... alors tout a commencé à fonctionner ... Mais vous êtes les commentaires qui m'inquiètent ... Êtes-vous sûr que c'est une mauvaise chose? – dicroce

1

Lorsqu'une fenêtre enfant est créée, elle peut interagir avec la fenêtre parent via SendMessage. Mais, notez que SendMessage à travers les threads de blocs de limite de fil contrairement à PostMessage. Si le thread de la fenêtre parent attend le thread fils et que le thread enfant tente de créer une fenêtre dont le parent se trouve dans ce thread, il s'agit d'un blocage.

En général, je ne pense pas que ce soit une bonne idée de faire une relation enfant-parent à travers les threads. Il peut très facilement faire une impasse.

+0

Il n'y a pas d'interaction entre parent et enfant ... Donc je ne sais pas à quoi servent les trucs SendMessage et PostMessage ... Comment êtes-vous sûr de votre deuxième paragraphe? Est-ce une limitation générale de Win32? – dicroce

+0

Oui, il s'agit d'une limitation Win32. Les relations de fenêtre parent-enfant ne doivent jamais traverser les limites de threads. Un autre symptôme qui en résulte est que DestroyWindow() ne fonctionnera pas correctement si vous détruisez une fenêtre parent dont les fenêtres filles ont été créées dans d'autres threads. –

+0

Dicroce, il existe un appel SendMessage implicite entre parent et enfant. Donc, vous feriez mieux de l'éviter. – minjang

0

Ceci est une question intéressante: Beaucoup de gars old school win32 m'ont dit que vous ne pouvez pas faire cela. En recherchant ceci, j'ai trouvé ce forum: SendMessage(). Ma théorie actuelle est que CreateWindowEx() doit envoyer un message (via SendMessage(), donc il bloque) à la fenêtre parent pour demander l'autorisation d'exister (ou au moins de notifier son existence) ... De toute façon, aussi longtemps que que le fil parent est libre de traiter ces messages, tout fonctionne ...

1

Il y a beaucoup de réponses ici disant que vous NE DEVEZ PAS essayer d'avoir des fenêtres enfant et parent sur des threads différents, et affirmant plutôt catégoriquement ne fonctionne pas.

Si tel était le cas, Windows mettrait certaines sauvegardes dans et tout simplement échouer lorsque vous avez tenté d'appeler CreateWindow. Maintenant, il y a certainement des problèmes de couplage de threads qui peuvent causer des problèmes majeurs, mais cela dit avec ces contraintes, c'est un scénario supporté.