Windows программа управляется событиями
. Это означает, что Вам, как программисту, полагается находиться в обороне. Пользователь будет бомбардировать Windows различными внешними действиями, а Windows будет бомбардировать вашу программу сообщениями, соответствующими этим действиям. Все, что Вы должны делать — это отвечать на сообщения. Рисунок ниже схематично показывает как все это работает.Каждое сообщение адресовано определенному окну. Когда Вы запрашиваете сообщение у Windows, система выяснит класс вашего окна, найдет связанную с ним оконную процедуру, и вызовет ее. Любое сообщение, посланное нашему окну может обрабатываться в нашей оконной процедуре. Нам остается только отреагировать на его. И что? Мы должны отвечать соответстветствующим образом на всевозможные сообщения Windows? Там их сотни! К счастью, нет! Мы должны перехватывать только те сообщения, в которых заинтересованы. Все остальные мы возвращаем обратно в Windows для обработки по умолчанию, используя DefWindowProc
.Windows получает различные события от клавиатуры, мыши, портов, и т.д. Каждое событие быстро преобразуется в сообщение. Windows посылает сообщения, соответствующим окнам. Например, все сообщения от клавиатуры идут к окну, которое в настоящее время имеет фокус ввода (активное окно). Сообщения мыши посылаются согласно позиции курсора мыши. Они обычно идут к окну, которое расположено непосредственно под курсором (если какая-нибудь программа не захватила мышь).
Все эти сообщения заканчиваются в очередях сообщений. Windows поддерживает очередь сообщений для каждой выполняющейся прикладной программы (фактически, для каждого потока). Ваша задача состоит в последовательном получении этих сообщений в так называемом цикле сообщений (message loop). Для этого программа должна вызывать GetMessage
. Затем вызывается DispatchMessage, чтобы отдать сообщение обратно Windows. Разве сама Windows не может посылать все эти сообщения самостоятельно? В принципе это возможно, но цикл сообщений дает вашей программе возможность посмотреть на них и, если это необходимо, выполнить некоторые дополнительные действия перед возвратом. Или не выполнять…Давайте рассмотрим WinMain
. Выполнение Windows программы не начинается с функции main — оно начинается с WinMain. Сначала, мы создаем winclass и регистрируем его. Затем мы создаем экземпляр окна (на основе только что зарегистрированного класса) и отображаем его. В общем случае WinMain вызывается с соответствующей директивой show. Пользователь может запустить приложение со свернутым или развернутым окном. Так что мы только следуем этой директиве. Затем мы запускаем цикл сообщения, в котором обрабатываем и посылаем сообщения до тех пор, пока GetMessage не возвратит 0. В этот момент параметр wparam сообщения будет содержать код возврата для всей программы.int WINAPI WinMain
char className [] = "Winnie";
WinClass winClass(WindowProcedure, className, hInst);
winClass.Register();
WinMaker win("Hello Windows!", className, hInst);
win.Show(cmdShow);
MSG msg;
int status;
while ((status = ::GetMessage
if (status == –1) return –1;
::DispatchMessage
}
return msg.wParam;
}
Функция API GetMessage
– интересный пример причудливой troolean (в противоположность традиционной Boolean) логики Microsoft. GetMessage определена таким образом, чтобы возвратить BOOL, но в документации определяется три варианта возвращаемых значений: ненулевых, нуля и –1. Я это не выдумал! Приведу цитату из справки:Если функция передает сообщение, иное чем WM_QUIT, возвращаемое значение отлично от нуля.
Если же функция выдает сообщение WM_QUIT, возвращаемое значение — нуль.
При возникновении ошибки возвращаемое значение равно –1.