Home > other >  Polling Windows native window events in a separate thread
Polling Windows native window events in a separate thread

Time:01-10

I need a Windows native window handle for a renderer, but I'm struggling to poll events correctly.

First, I create a window, which works fine on its own:

WNDPROC Window::MakeWindow( LPCWSTR _title, unsigned int _width, unsigned int _height ) {
    HINSTANCE hInstance = GetModuleHandle( NULL );
    HWND hwnd;

    //Step 1: Registering the Window Class
    m_WindowClass.cbSize        = sizeof(WNDCLASSEX);
    m_WindowClass.style         = 0;
    m_WindowClass.lpfnWndProc   = WindowProc;
    m_WindowClass.cbClsExtra    = 0;
    m_WindowClass.cbWndExtra    = 0;
    m_WindowClass.hInstance     = hInstance;
    m_WindowClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    m_WindowClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
    m_WindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW 1);
    m_WindowClass.lpszMenuName  = NULL;
    m_WindowClass.lpszClassName = (LPCWSTR)g_szClassName;
    m_WindowClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&m_WindowClass))
    {
        MessageBox(NULL, L"Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        (LPCWSTR)g_szClassName,                     // Window class
        _title,    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, 
        _width, _height,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if(hwnd == NULL)
    {
        MessageBox(NULL, L"Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, 1);
    UpdateWindow(hwnd);

    PollEvents();

    return NULL;
}

After creating the window, I want to check for user inputs. In the code snippets I copied, they did it like this:

void PollEvents() {
    MSG Msg;

    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
}

But, since this blocks my code, I tried using a separate thread to do this. So, at the end of my window creation, I create a thread like so:

m_PollThread = new std::thread(PollEvents);

To test if it's working, I wrote this main() function:

int main() {
    // poll thread is created here
    Window* window = new Window( "Test Window", 1024, 720 );

    while (true) {
        Sleep(10);
    };

    // poll thread is closed/awaited here
    delete window;
}

But, the window ends up frozen, so just the while loop is executed while the other thread seems to do nothing.

CodePudding user response:

Only the thread that creates a window can receive messages for that window. You cannot create a window in one thread and then receive messages for that window in another thread.

GetMessage() blocks until it receives a message, so your code freezes because you are calling GetMessage() in a thread that has no window to receive messages for, and the thread that created the window is not processing any messages for that window.

So, if you want to poll events periodically, in the creating thread, without blocking your code, use PeekMessage() instead of GetMessage(), eg:

void PollEvents() {
    MSG Msg;
    while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
}

Otherwise, you will have to move both the window creation and the event loop into your worker thread.

  • Related