Search code examples
winapiwindowdeadlockcreatewindow

Win32 CreateWindow() call hangs in child thread?


I'm working on a portability layer for OpenGL (abstracts the glX and wgl stuff for Linux and Windows)... Anyhow, it has a method for creating a Window... If you don't pass in a parent, you get a real window with a frame... If you pass in a parent, you get a borderless, frameless window...

This works fine, as long as I do it all on 1 thread... As soon as another thread tries to create a child window, the app deadlocks in the win32 call "CreateWindow()". Any ideas?


Solution

  • This is not a real answer, but since so many people seem to believe that Win32 forbids creating children in other threads than the parent, I feel obliged to post a demonstration to the contrary.

    The code below demonstrates creation of a child window on a parent belonging to a different process. It accepts a window handle value as a command-line parameter and creates a child window on that 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;
    }
    

    Compile this with the following command (using MSVC command line environment):

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

    Then use Spy++ or some other tool to obtain handle value of any window -- e.g. of Notepad or the browser you're viewing this site in. Let's assume it's 0x00001234. Then run the compiled sample with t.exe 0x1234. Use Ctrl-C to terminate t.exe (or just close the console window).