【问题标题】:Polling Windows native window events in a separate thread在单独的线程中轮询 Windows 本机窗口事件
【发布时间】:2023-01-10 04:10:47
【问题描述】:

我需要一个用于渲染器的 Windows 本机窗口句柄,但我正在努力正确轮询事件。

首先,我创建了一个窗口,它自己运行良好:

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

创建窗口后,我想检查用户输入。在我复制的代码 sn-ps 中,他们是这样做的:

void PollEvents() {
    MSG Msg;

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

但是,由于这会阻塞我的代码,所以我尝试使用单独的线程来执行此操作。因此,在我的窗口创建结束时,我创建了一个线程,如下所示:

m_PollThread = new std::thread(PollEvents);

为了测试它是否有效,我写了这个 main() 函数:

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

但是,窗口最终冻结了,所以只执行 while 循环,而另一个线程似乎什么都不做。

【问题讨论】:

  • 此问题的显示代码不符合 Stackoverflow 显示 minimal reproducible example 的要求。因此,这里的任何人都不太可能最终回答这个问题。但最多只能猜测。你需要edit你的问题来展示一个最小的例子,不超过一两页代码(“最小”部分),其他人都可以剪切/粘贴完全如图所示、编译、运行和重现所描述的问题(“可重现”部分,这包括任何辅助信息,如程序的任何输入)。有关详细信息,请参阅How to Ask
  • 好的,抱歉,我会马上解决
  • 在此代码中,调用 PollEvents 的线程在哪里?
  • 为什么要为 Windows 事件单独线程而不为其他工作单独线程?
  • @i486 这就是它不起作用的原因吗?因为它无法访问另一个线程中的窗口?

标签: c++ windows user-interface winapi


【解决方案1】:

只有创建窗口的线程才能接收该窗口的消息。您不能在一个线程中创建一个窗口,然后在另一个线程中接收该窗口的消息。

GetMessage() 会阻塞,直到它收到一条消息,所以您的代码会冻结,因为您在没有窗口接收消息的线程中调用 GetMessage(),并且创建该窗口的线程未处理该窗口的任何消息。

因此,如果您想在创建线程中定期轮询事件而不阻塞您的代码,请使用 PeekMessage() 而不是 GetMessage(),例如:

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

否则,您将不得不搬家两个都窗口创建和事件循环进入您的工作线程。

【讨论】:

    猜你喜欢
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    相关资源
    最近更新 更多