Application.DoEvents отправляет сообщения в отдельную ветку? - PullRequest
0 голосов
/ 20 ноября 2011

Я пытался понять циклы событий (не так хорошо) в целом, и я прочитал, что цикл сообщений Windows является однопоточным. Если это так, как может работать Application.DoEvents? Разве цикл обработки событий не обрабатывает одно сообщение за раз и блокируется во время обработки каждого сообщения / события? Разве цикл сообщений не должен существовать в потоке, отличном от того, который обрабатывает сообщение для Application.DoEvents, чтобы это было возможно? Если существуют отдельные потоки, какой из них мы называем «основным» потоком? Я уверен, что упускаю что-то очень простое, я просто не знаю, что это такое.

1 Ответ

0 голосов
/ 20 ноября 2011

Я провожу большую часть дня, выясняя это (если что-то, что я скажу, неверно, пожалуйста, прокомментируйте и дайте мне знать, чтобы я мог это исправить).Я действительно должен был создать старое приложение Win32 и создать цикл сообщений сам (я довольно постоянный SOB).Таким образом, есть функция WinMain, которая запускает цикл обработки сообщений, который выглядит следующим образом:

while (GetMessage(&msg, NULL, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

Особенность GetMessage () заключается в том, что он блокируется, пока сообщение не станет доступным в очереди сообщений.Если вы запустите Windowed-приложение и просто сидите там и смотрите на окно (не вызывайте никаких действий, которые бы отправили сообщение в очередь), основной поток (поток, в котором было создано окно) приостанавливается на GetMessage (),Теперь, когда сообщение действительно публикуется, мы входим в цикл while (то есть, если сообщение не завершено, что равно 0).DispatchMessage () - интересная функция здесь.Эта функция в конечном итоге приведет к (в .NET) событиям, вызываемым элементами управления и выполнением EventHandlers.Что меня озадачило, если стек вызовов GetMessage () / DispatchMessage () /.../ EventHandler, как это возможно для Application.DoEvents () обрабатывать сообщения?Ну, это довольно просто.DoEvents в Win32 будет выглядеть следующим образом:

void DoEvents()
{
   MSG msg;
   HACCEL hAccelTable;

   hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDC_TESTWIN32));

   // Main message loop:
   while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0)
   {
       if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
       {
           TranslateMessage(&msg);
           DispatchMessage(&msg);
       }
   }
}

Таким образом, DoEvents () фактически запускает другой цикл для обработки событий, находясь внутри DispatchMessage () начального цикла сообщения! Ключевым отличием является то, что вместо использования GetMessage (), который блокирует, пока в очереди нет сообщения, мы используем PeekMessage (), который возвращает 0 и существует цикл, когда в очереди больше нет сообщений.

Так что, если мы дважды нажмем кнопку и в EventHandler этой кнопки у нас будет вызов DoEvents ()?Первоначальный цикл обработки событий обработает первый щелчок и вызовет событиеВо время выполнения EventHandler при вызове DoEvents () событие будет запущено второй раз, а EventHandler будет введен снова (что-то вроде рекурсивного вызова).Это страшно!

Итак, в конце концов, все происходит в одном потоке, и DoEvents () фактически блокируется, пока все сообщения не будут обработаны, а затем возвращается.Теперь я пойду спать на пару дней.

...