Win32 CreateWindow()调用在子线程中挂起?

时间:2009-11-18 21:06:41

标签: winapi window deadlock createwindow

我正在为OpenGL开发一个可移植层(抽象出用于Linux和Windows的glX和wgl)...无论如何,它有一个创建窗口的方法...如果你没有传入父,你得到一个带框架的真实窗口...如果你传入一个父母,你会得到一个无边框的无框窗口......

这个工作正常,只要我在1个线程上完成所有操作...一旦另一个线程尝试创建子窗口,应用程序就会在win32调用“CreateWindow()”中死锁。有什么想法吗?

5 个答案:

答案 0 :(得分: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 ++或其他工具获取任何窗口的句柄值 - 例如记事本或您正在浏览此网站的浏览器。让我们假设它是0x00001234。然后使用t.exe 0x1234运行已编译的示例。使用Ctrl-C终止t.exe(或只关闭控制台窗口)。

答案 1 :(得分:1)

创建子窗口时,它可以通过SendMessage与父窗口进行交互。但是,请注意跨越线程边界的SendMessage阻止线程与PostMessage不同。如果父窗口的线程正在等待子线程,并且子线程正在尝试创建父窗口在该线程中的窗口,那么它就是死锁。

一般来说,我认为跨线程建立子父关系并不是一个好主意。它很容易造成死锁。

答案 2 :(得分:1)

这里有很多回复说你不得试图在不同的线程上设置子窗口和父窗口,而是强调说明它不起作用。

如果是这样的话,Windows会提供一些保护措施,并在您尝试调用CreateWindow时失败。 现在,确实存在可能导致重大问题的线程耦合问题,但是,在这些约束条件下,这是一个受支持的场景。

答案 3 :(得分:0)

这是一个有趣的问题:很多老派win32的家伙告诉我你不能这样做。在研究这个问题时,我找到了这个论坛:SendMessage()。我当前的理论是,CreateWindowEx()必须向父窗口发送一条消息(通过SendMessage(),因此它会阻塞)以请求存在的权限(或至少通知它的存在)...无论如何,只要父线程可以自由处理这些消息,一切正常......

答案 4 :(得分:-1)

窗口与创建它的线程相关联(更具体地说,与该线程的消息队列相关联)。父窗口不能驻留在与其子窗口不同的线程中。