WM_WINDOWPOSCHANGING 0 &WINDOWPOS
cообщение указывает на то, что положение или состояние окна изменяется. Параметр lParam содержит указатель на структуру WINDOWPOS, описывающую положение окна и выполняемую операцию. Изменив соответствующие поля структуры можно изменить положение и размеры окна или повлиять на выполняемые действия.
<сообщения активации окна(или всего приложения)>
если окно просто активируется, то обычно следующее сообщение WM_WINDOWPOSCHANGED, завершающее всю цепочку, без всех рассматриваемых нами промежуточных сообщений, применяемых при изменении размеров или положения.
WM_GETMINMAXINFO 0 &MINMAXINFO
проверка новых размеров окна
WM_NCCALCSIZE flag &NCCALCSIZE_PARAMS
определение размера внутренней области
WM_NCPAINT 0 0
отображение внешней области окна
WM_ERASEBKGND hDC 0
очистка фона окна
WM_WINDOWPOSCHANGED 0 &WINDOWPOS
состояние окна изменено. Параметр lParam является указателем на структуру WINDOWPOS, содержащую данные о положении и размерах окна. Сообщения WM_WINDOWPOSCHANGING ... WM_WINDOWPOSCHANGED часто не содержат между собой никаких иных сообщений, если состояние, размер и положение не изменились. (Часто это бывает, если окно активируется в ответ на “щелчок мышкой”).
WM_MOVE 0 y & x
WM_SIZE type height & width
Эти сообщения информируют о новом положении и размерах окна. Они посылаются при соответствующих изменениях процедурой DefWindowProc() при обработке сообщения WM_WINDOWPOSCHANGED. Хотя в документации указано, что можно несколько ускорить работу, перехватывая вместо WM_MOVE и WM_SIZE сообщение WM_WINDOWPOSCHANGED и не вызывая при этом DefWindowProc(), но использовать этот прием нужно очень осторожно - так как сообщения WM_SIZE и WM_MOVE используются MDI окнами.
Рассмотренная нами цепочка сообщений порождается функцией SetWindowPos (или эквивалентной) и эти сообщения непосредственно передаются окну, а не посылаются.
WM_PAINT 0 0
рисование внутренней области окна. В результате выполненной операции окно (или его часть), как правило, маркируется как неверное, что приводит к перерисовке окна. Сообщение WM_PAINT извлекается из очереди сообщений и может обрабатываться с некоторой задержкой после изменения размеров, положения или состояния окна.
После вызова ShowWindow() в WinMain() обычно следует процедура UpdateWindow(). Эта процедура проверяет наличие неверных прямоугольников и, если они есть, передает сообщение WM_PAINT (не ставит в очередь, а вызывает обработку этого сообщения).
Обработка UpdateWindow():
WM_PAINT 0 0
Нарисовать внутреннюю область окна. Если для получения хендла контекста устройства используется функция BeginPaint(), то она может передавать сообщение WM_ERASEBKGND для очистки фона в неверном прямоугольнике (если при его создании было указано, что фон должен быть восстановлен).
WM_ERASEBKGND hDC 0
Обрабатывая это сообщение, мы должны закрасить фон окна, используя переданный нам хендл контекста устройства, или вызвать обработку по умолчанию.
Уничтожение окна
Для уничтожения окна надо вызвать функцию DestroyWindow(), которая выполнит требуемые действия по закрытию окна. Причем при этом посылаются:
<сообщения деактивации (если надо)>
Иногда бывает так, что сообщения деактивации окна не поступают, происходит деактивация приложения и уничтожение окна;
WM_DESTROY 0 0
Уничтожение внутренней области окна.
WM_NCDESTROY 0 0
Уничтожение внешней области окна.
Сообщения WM_DESTROY и WM_NCDESTROY являются последними сообщениями, получаемыми окном. После WM_NCDESTROY окно не получит ни одного сообщения, поэтому Вы можете смело разрушать все созданные для окна структуры данных.
Сообщение WM_DESTROY удобно применять для уничтожения всех объектов, связянных с данным окном, в том числе и дочерних окон.
Внимание: во время обработки сообщений WM_DESTROY и WM_NCDESTROY нельзя активировать каких-либо дочерних окон. (В том числе нельзя применять функцию MessageBox, передавая ей хендл уничтожаемого окна в качестве родительского) - это приведет к появлению дополнительных сообщений, направленных уничтожаемому окну, и, в конечном результате, к ошибке “General protection fault...”
Если Вы хотите получить подтверждение перед закрытием окна, то Вы должны использовать сообщение WM_CLOSE. Функция DefWindowProc, обрабатывая это сообщение, вызывает функцию DestroyWindow. Вы можете легко вставить собственные средства для обработки сообщения WM_CLOSE, и вызывать DestroyWindow или процедуру по умолчанию только при положительном ответе на запрос. Сообщение WM_CLOSE лучше посылать, а не передавать.
Событие WM_CLOSE используется самой средой, причем обычно предваряется последовательностью сообщений, приводящей к закрытию окна. Например такой: активация системного меню — выбор пункта ‘Close’ — завершение меню — посылка WM_SYSCOMMAND с параметром SC_CLOSE — посылка WM_CLOSE — уничтожение окна.
Существует еще два сообщения, которое могут привести к закрытию окна:
WM_QUERYENDSESSION 0 0
Это сообщение информирует о том, что Windows заканчивает работу когда приложение активно. Оно посылается ко всем запущеным приложениям. Если все возвращают TRUE, то Windows завершает работу.
Обрабатывая это сообщение, Вы должны вернуть TRUE, если Ваше приложение может быть завершено, или FALSE в противном случае. При этом Windows продолжит нормальную работу.
WM_ENDSESSION TRUE/FALSE 0
Это сообщение посылается активному приложению, если оно ответило TRUE на сообщение WM_QUERYENDSESSION. Флаг в параметре ‘wPar’ равный TRUE указывает, что работа Windows может завершиться сразу после обработки этого сообщения. Вы не обязаны уничтожать окно и посылать себе WM_QUIT для завершения работы, если завершается работа всего Windows.
Клавиатура. Сообщения клавиатуры
Сейчас мы рассмотрим основные сообщения клавиатуры и несколько функций, предназначенных для работы с ней. Когда мы нажимаем на любую кнопку, наше (точнее - активное) приложение получает сообщение
WM_KEYDOWN VkCode dwKeyData
Параметр wPar содержит виртуальный код нажатой клавиши. В Windows поддерживается специальная система нумерации клавиш, которая представлена их виртуальными номерами.
Параметр dwKeyData присутствует для всех сообщений клавиатуры и содержит информацию о текущем событии.
Для большинства клавиш их виртуальный код соответствует той заглавной букве, которая на них нанесена (для английской клавиатуры). Например, виртуальный код клавиши A равен ASCII коду символа ‘A’. Для тех клавиш, которые не соответствуют буквам и символам предусмотрены специальные номера, например VK_F6 для клавиши F6, VK_MENU для клавиши Alt, VK_RETURN для клавиши Enter.
Если посмотреть на список виртуальных кодов (это можно сделать в WINDOWS.H), то мы увидим несколько странных клавиш:
VK_LBUTTON, VK_RBUTTON, VK_MBUTTON
соответствующих кнопкам мыши. Однако эти виртуальные коды используются несколько иначе, и приложение не получает сообщений WM_KEYDOWN при нажатии кнопок мыши.
Параметр dwKeyData присутствует для всех сообщений клавиатуры и содержит следующую информацию:
WM_KEYUP VkCode dwKeyData
Кроме сообщения WM_KEYDOWN Windows посылает сообщения WM_KEYUP при отпускании клавиши. Параметры этого сообщения такие же, как и у сообщения WM_KEYDOWN.
Когда Ваше приложение извлекает из очереди сообщение WM_KEYDOWN, то обычно оно транслируется с помощью функции TranslateMessage (это происходит в главном цикле обработки сообщений). Эта функция осуществляет трансляцию сообщений клавиатуры и в результате посылает сообщения WM_CHAR, соответствующие нажатому символу или WM_DEADCHAR.
WM_CHAR nCharacter dwKeyData
Сообщает приложению о том, что нажатая клавиша соответствует данному (nCharacter) символу. Если Вы разрабатываете, например, собственный редактор, то Вы должны обрабатывать сообщения WM_CHAR для формирования текста, а не сообщения WM_KEYDOWN.
WM_DEADCHAR nDeadChar dwKeyData
Это сообщение информирует приложение о нажатии так называемой Dead-Key. Dead-Key клавиши обычно соответствуют акцентным символам. Так, например, немецкая клавиатура имеет несколько Dead-Key, скажем ‘. Если нажать эту клавишу, а, затем, букву A, то результат должен соответствовать A с ударением. При этом нажатый ‘ сам по себе не соответствует никакому символу (это Dead-Key), а служит модификатором для следующей клавиши. Таким образом на последовательность сообщений WM_KEYDOWN для клавиш ‘ и A будут генерироваться сообщения WM_DEADCHAR для ‘ и WM_CHAR для A с ударением.
Окно, имеющее фокус ввода, и активное окно
Помимо рассмотренных четырех сообщений Windows использует еще 4 сообщения, содержащих такую же информацию, как и уже рассмотренные сообщения клавиатуры:
WM_SYSKEYDOWN VkCode dwKeyData
WM_SYSKEYUP VkCode dwKeyData
WM_SYSCHAR nCharacter dwKeyData
WM_SYSDEADCHAR nDeadChar dwKeyData
Обычно эти сообщения посылаются при нажатии клавиш совместно с клавишей Alt. Вы обязательно должны предусмотреть обработку этих сообщений по умолчанию, так как, если этого не делать, то будет нарушен стандартный интерфейс Windows – перестануть работать такие клавиши как Alt–Tab, Ctrl–Esc и пр.
Сейчас мы должны будем разобраться в различиях понятий “активное окно” и “окно, имеющее фокус ввода”. Сформулируем несколько правил, позволяющих различать эти понятия.
· окно, имеющее фокус ввода, всегда активно.
· в любой момент времени существует активное окно.
· минимизированное окно не может иметь фокуса ввода, если активное окно минимизировано, то фокус ввода не принадлежит никакому окну.
· если активное окно не минимизировано, то оно имеет фокус ввода.
Все, что мы сейчас выяснили о сообщениях клавиатуры относится к окну, имеющему фокус ввода. Если наше окно активно и не имеет фокуса ввода, то вместо сообщений WM_KEYDOWN, WM_KEYUP, WM_CHAR и WM_DEADCHAR оно будет получать сообщения WM_SYSKEYDOWN, WM_SYSKEYUP, WM_SYSCHAR и WM_SYSDEADCHAR.
Для чего в Windows используются эти два понятия? Представим себе, что мы разрабатываем какой-либо редактор. Для управления им мы используем обычные (не системные) сообщения клавиатуры. Теперь мы минимизировали наш редактор и сделали его активным. Если бы при этом он по-прежнему получал обычные сообщения клавиатуры, то пришлось бы специально предусматривать блокировку ввода данных в минимизированном состоянии - так как работа “в слепую” вряд-ли будет удобна. А, так как в минимизированном состоянии он теряет фокус ввода, то вместо обычных сообщений он будет получать системные, что исключит нежелательный эффект.