思考一种不同的方式来运行win32事件循环没有WndProc

Thoughts on a different way to running a win32 event loop without WndProc?

本文关键字:win32 运行 事件 循环 WndProc 方式 一种      更新时间:2023-10-16

在处理多线程、回调、win32 api函数和其他麻烦的时候,我收到了一个想法事件。(哈哈)

如果,而不是定义一个全局(或静态设计类时)回调函数,而不是分配DefWindowProclpfnWndProc注册窗口类,然后在一个单独的线程上运行整个事件循环?

这样我就不必在类中实现回调时破解this问题主线程继续执行,将您从该死的while循环中解放出来,允许您做任何事情,甚至打开另一个窗口(耶!)

"正常"方式:

LRESULT CALLBACK WndProc(...)
{
    ... // process event information
    return DefWindowProc(...);
}
int CALLBACK WinMain(...)
{
    ... // initialize whatever needs initializing :)
    WNDCLASSEX wc;
    ...
    wc.lpfnWndProc = WndProc;
    ... // register the class, create the window, etc...
   MSG msg;
   while(GetMessage(&msg, 0, 0, 0) != 0)
   {
        ... // TranslateMessage(&msg) if you want/need it
        DispatchMessage(&msg); // dispatches the message to WndProc
   }
   return static_cast<int>(msg.wParam);
}

我的新发现:

DWORD WINAPI MyAwesomeEventLoop(void* data) // must be static in a class
{
    ... // do whatever you need with the data
    MSG msg;
    while(GetMessage(&msg, 0, 0, 0) != 0)
    {
        ... // TranslateMessage(&msg) if you want/need it
        ... // process event information
            // call PostQuitMessage(0) to leave the loop
    }
    return static_cast<DWORD>(msg.wParam);
 }
int CALLBACK WndProc(...)
{
    ...
    WNDCLASSEX wc;
    ...
    wc.lpfnWndProc = DefWindowProc;
    ...
    HANDLE threadHandle = 0;
    // use "this" as the 4th parameter when implementing in a class
    threadHandle = CreateThread(0, 0, MyAwesomeEventLoop, 0, 0, 0);
    ... // you are now free to do whatever you want! :)
    // waits untill the thread finishes
    // hopefully because PostQuitMessage(0) was called
    WaitForSingleObject(threadHandle, INFINITE);
    DWORD returnValue = 0;
    GetExitCodeThread(threadHandle, &returnValue);
    CloseHandle(threadHandle);
    ...
    return static_cast<int>(returnValue);
 }

你们觉得怎么样?

GetMessage docs on MSDN:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644936 (v = vs.85) . aspx

阅读第一句话:"从调用线程的消息队列中检索消息。"

窗口的消息队列绑定到创建它的线程。由于您在主线程上创建了窗口,因此在新线程上运行的事件循环将不会接收该窗口的任何消息。如果您想在另一个线程上运行事件循环,则需要先创建线程,然后在该线程上创建窗口。

这并没有真正为您带来任何东西,只是现在您在通用事件循环中拥有了特定于窗口类的事件处理代码,这非常丑陋。如果需要后台工作,请使用工作线程。将GUI和事件反应器保留在主线程中,并按照文档使用回调。

如果你有一个类的实例处理窗口,即使在单线程代码中,你也不应该让它们全局化(否则你的将在未来遭受痛苦的重构)。