2009-11-18 2 views
1

Я работаю над уровнем переносимости для OpenGL (абстрагирует glX и wgl-материалы для Linux и Windows) ... Во всяком случае, у него есть метод для создания окна ... Если вы не проходите родительский, вы получите реальное окно с рамкой ... Если вы перейдете к родительскому, вы получите окно без рамки без рамки ...Win32 CreateWindow() вызывает зависание в дочернем потоке?

Это прекрасно работает, если я делаю все это на одной ветке ... Как вскоре, когда другой поток попытается создать дочернее окно, приложение блокирует вызов win32 «CreateWindow()». Есть идеи?

ответ

5

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

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

// 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; 
} 

Компиляция это с помощью следующей команды (с использованием MSVC среды командной строки):

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

Затем с помощью Spy ++ или какой-либо другой инструмент, чтобы получить значение дескриптора любого окна - например, «Блокнот» или браузер, на котором вы просматриваете этот сайт. Предположим, что это 0x000. Затем запустите скомпилированный образец с t.exe 0x1234. Используйте Ctrl-C для завершения t.exe (или просто закройте окно консоли).

-1

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

+0

Это не то, что я пытаюсь сделать. Я хочу, чтобы каждый поток заботился только о тех окнах, которые он создает ... Мне просто нужно создать окно с родителем, созданным другим потоком ... – dicroce

+0

Это НЕ РАБОТАЕТ. Вы НЕ МОЖЕТЕ создать родительское окно в одном потоке, а затем создать дочернее окно в другом потоке.Они ДОЛЖНЫ быть в одной теме. –

+0

Хм ... Ну, я на самом деле это заработал ... В принципе, мне просто нужно было перевести насос с насосами родителей ... тогда все начиналось ... Но ты меня беспокоишь ... Как вы уверены в том, что это плохо? – dicroce

1

Когда дочернее окно создано, оно может взаимодействовать с родительским окном через SendMessage. Но, обратите внимание, что SendMessage по потоку граничит с потоками, в отличие от PostMessage. Если поток родительского окна ждет дочерний поток, а дочерний поток пытается создать окно, чей родитель находится в этом потоке, то это тупик.

В целом, я не думаю, что это хорошая идея - установить отношения между родителями и родителями. Он может очень легко сделать тупик.

+0

Не существует взаимодействия между родителем и ребенком ... Поэтому я не знаю, что такое материал SendMessage и PostMessage ... Насколько вы уверены в своем втором абзаце? Это общее ограничение Win32? – dicroce

+0

Да, это ограничение Win32. Отношения родительского окна никогда не должны пересекать границы потоков. Другим симптомом, который является результатом этого является DestroyWindow(), не будет работать корректно, если уничтожит родительское окно, дочерние окна которого были созданы в других потоках. –

+0

Dicroce, существует неявный вызов SendMessage между родителем и дочерним. Поэтому вам лучше избегать этого. – minjang

0

Это интересный вопрос: многие из старых школьных парней win32 сказали мне, что вы НЕ МОЖЕТЕ это сделать. В этом я нашел этот форум: SendMessage(). Моя нынешняя теория заключается в том, что CreateWindowEx() должен отправить сообщение (через SendMessage(), чтобы оно блокировалось) в родительское окно, чтобы попросить разрешения на существование (или, по крайней мере, уведомить о его существовании) ... Во всяком случае, до тех пор, пока этот родительский поток может обрабатывать эти сообщения бесплатно, все это работает ...

1

Здесь есть много ответов, в которых говорится, что вы НЕ ДОЛЖНЫ пытаться иметь дочерние и родительские окна на разных потоках, и довольно решительно заявляя, что это будет не работа.

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

Смежные вопросы