Причина в том, что Windows берет на себя обработку сообщений, когда отображается что-то вроде меню приложения или окна сообщения, и тот цикл обработки сообщений, который использует Windows, не вызовет ваш метод DoSomething()
. Это может быть трудно визуализировать, поэтому я постараюсь пройтись по происходящему:
- Когда кто-то открывает ваше меню, в ваше окно отправляется сообщение с просьбой нарисовать окно.
DispatchMessage()
отправляет сообщение на ваш WndProc
, как и все другие сообщения.
- Поскольку вы не обрабатываете это сообщение, оно передается в Windows (так как ваш
WndProc
более вероятно вызывает DefWindowProc
)
- В качестве операции по умолчанию Windows рисует меню и запускает другой цикл сообщений по умолчанию , который не будет вызывать
DoSomething()
- Этот цикл извлекает сообщения, предназначенные для вашего приложения, и отправляет их в ваше приложение, вызывая
WndProc
, чтобы ваше приложение не зависало и продолжало работать (за исключением вызова DoSomething()
).
- Как только меню закроется, управление вернется в ваш цикл сообщений (только в этот момент вызов
DispatchMessage()
с самого начала вернется)
Другими словами, когда отображается меню, ваш цикл сообщений заменяется циклом по умолчанию, который выглядит следующим образом (например)
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
, который, как вы можете видеть, не будет вызывать ваш DoSomething()
метод.
Чтобы проверить это, попробуйте приостановить ваш код в отладчике, когда меню не отображается, а когда оно есть. Если вы видите стек вызовов, вы увидите, что при отображении меню сообщения обрабатываются циклом сообщений Windows, а не вашим.
Единственный обходной путь, о котором я могу подумать (без многопоточности), - это если вы запускаете таймер и обрабатываете сообщение WM_TIMER
, вызывая DoSomething()
, но это не будет идеальным решением (поскольку я предполагаю, что ваше намерение состоит в том, чтобы вызвать DoSomething()
только когда не осталось сообщений для обработки).