Win32 CreateWindow () вызов зависает в дочернем потоке? - PullRequest
1 голос
/ 19 ноября 2009

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

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

Ответы [ 5 ]

5 голосов
/ 19 ноября 2009

Это не реальный ответ, но так как многие люди, кажется, считают, что 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 ++ или другой инструмент для получения значения дескриптора любого окна, например, Блокнот или браузер, в котором вы просматриваете этот сайт. Предположим, это 0x00001234. Затем запустите скомпилированный пример с t.exe 0x1234. Используйте Ctrl-C для завершения t.exe (или просто закройте окно консоли).

1 голос
/ 19 ноября 2009

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

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

1 голос
/ 19 ноября 2009

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

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

0 голосов
/ 19 ноября 2009

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

0 голосов
/ 19 ноября 2009

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

...