Мысли о другом способе запуска цикла событий win32 без WndProc? - PullRequest
5 голосов
/ 03 декабря 2011

Пока возился с многопоточностью, обратными вызовами, функциями win32 api и другими неприятными проблемами, я получил событие идеи.(хе-хе)

Что если вместо определения глобальной (или статической при разработке класса) функции обратного вызова я вместо присвоения lpfnWndProc назначил DefWindowProc для регистрации класса окна, а затем запустил все событиецикл в отдельном потоке?

Таким образом, мне не нужно взламывать проблему 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);
 }

Что вы, ребята, думаете?

Ответы [ 2 ]

13 голосов
/ 03 декабря 2011

Документы GetMessage на MSDN:

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

Прочитайте первое предложение: «Извлекает сообщение из очереди сообщений вызывающего потока.»

Очередь сообщений дляокно связано с темой, в которой оно было создано.Поскольку вы создали окно в главном потоке, ваш цикл обработки событий, запущенный в новом потоке, просто не будет получать никаких сообщений для этого окна.Если вы хотите запустить цикл обработки событий в другом потоке, вам необходимо сначала создать поток, а затем создать окно в этом потоке.

2 голосов
/ 03 декабря 2011

Это на самом деле ничего не покупает, за исключением того, что теперь у вас есть код обработки событий, относящийся к классу окна, в общем цикле событий, что просто ужасно.Если вам нужна фоновая работа, используйте рабочие потоки.Держите GUI и реактор событий внутри основного потока и используйте обратные вызовы, как описано.

И если у вас есть класс, экземпляры которого обрабатывают окна, вы не должны делать их глобальными даже в однопоточном коде (иливы будете страдать от болезненного рефакторинга в будущем).

...