Давайте рассмотрим WinMain. Выполнение Windows программы не начинается с функции main — оно начинается с WinMain. Сначала, мы создаем winclass и регистрируем его. Затем мы создаем экземпляр окна (на основе только что зарегистрированного класса) и отображаем его. В общем случае WinMain вызывается с соответствующей директивой show. Пользователь может запустить приложение со свернутым или развернутым окном. Так что мы только следуем этой директиве. Затем мы запускаем цикл сообщения, в котором обрабатываем и посылаем сообщения до тех пор, пока GetMessageне возвратит 0. В этот момент параметр wparam сообщения будет содержать код возврата для всей программы.
int WINAPI WinMain(hinstance hinst, hinstance hprevinst, char * cmdParam, int cmdShow) {
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(&msg, 0, 0, 0)) != 0) {
if (status == –1) return –1;
:: DispatchMessage(&msg);
}
return msg.wParam;
}
Функция API GetMessage– интересный пример причудливой troolean (в противоположность традиционной Boolean) логики Microsoft. GetMessageопределена таким образом, чтобы возвратить BOOL, но в документации определяется три варианта возвращаемых значений: ненулевых, нуля и –1. Я это не выдумал! Приведу цитату из справки:
Если функция передает сообщение, иное чем WM_QUIT, возвращаемое значение отлично от нуля.
Если же функция выдает сообщение WM_QUIT, возвращаемое значение — нуль.
При возникновении ошибки возвращаемое значение равно –1.
Другая часть Windows программы — оконная процедура. Помните, что Windows вызывает ее при обработке всех сообщений. Эти сообщения могут игнорироваться, если их пересылать к DefWindowProc. Только одно сообщение мы всегда обязаны перехватывать. Это WM_DESTROY, посылаемое самой Windows в тот момент, когда пользователь закрывает окно (нажимая кнопку закрытия в заголовке окна). Стандартный ответ на WM_DESTROY заключается в посылке сообщения о выходе из программы со значением нуля в качестве кода возврата. Вот и все, что можно сказать по данной теме.
// Window Procedure called by Windows
LRESULT CALLBACK WindowProcedure(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_DESTROY:
:: PostQuitMessage(0);
return 0;
}
return :: DefWindowProc(hwnd, message, wparam, lparam);
}
Выше рассмотрена самая "уродливая" и менее всего поддающаяся инкапсуляции (при попытке использовать объектно-ориентированный подход) часть Windows . Она станет гораздо лучше, если разрабатывать программу так, как это предлагается в обобщенной Windows программе.
Windows и «Модель-Вид-Контроллер »
Обобщенная Windows программа
Перевод А. И. Легалова
Англоязычный оригинал находится на сервере компании Reliable Software
Эта программа использует набор базовых классов, которые инкапсулируют Windows API
• Controller (Контроллер) — Мост между оконной процедурой и объектно-ориентированным миром.
• View (Вид) — Инкапсулирует вывод Windows программы.
• Canvas (Холст) — Инкапсулирует различные контексты устройств и действия, которые Вы можете сделать с их использованием.
• Model (Модель) — Работник и мозг вашей программы. Вообще не имеет дело с Windows.
Обратите внимание: это Win32 программа — она м.б. запущена под Windows 95, 98, NT, 2000, Me.
Обратите внимание: _set_new_handler — это специфика Microsoft. Если вы используете другой компилятор, то скорее удалите эту строку из кода. Согласно текущему стандарту C++, оператор new должен выбрасывать исключения в любом случае ( VC++ сейчас тоже поддерживает стандарт. А.Л. ).
Обратите внимание: Старые компиляторы могут иметь проблемы с шаблонами ( Вряд ли кто использует такие старые компиляторы для программирования под Windows. А.Л. ). В этом случае вы можете заменить используемые шаблоны типа Win[Get/Set]Longпрямыми вызовами Get/SetWindowLong. Например, вместо вызова
Controller * pCtrl = WinGetLong (hwnd);
вы можете записать
Controller * pCtrl = reinterpret_cast (::GetWindowLong (hwnd, GWL_USERDATA));
Загрузка упакованных исходных текстов Generic(11 кб).
WinMain
При запуске WinMain, создается класс окна и главное окно нашего приложения. Я инкапсулировал эти действия внутри двух классов: WinClassи WinMaker. WinClass может также сообщать нам о том, что уже выполняются другие экземпляры нашей программы. Когда подобное случается в нашем примере, мы просто активизируем уже выполняющийся экземпляр программы и выходим из запускаемого приложения. Так необходимо поступать тогда, когда Вы хотите, чтобы в один момент времени выполнялся только один экземпляр вашей программы.
Читать дальше