Учебное пособие: Окна приложений в среде Windows
В большинстве случаев, функции Windows API, работающие с хендлом модуля, корректно выполняются при передачи им хендла копии приложения, так что в документации возможен некоторый разнобой в используемых терминах.
В Win32 хендл модуля является синонимом хендла копии приложения. В документации встречаются оба термина, как они перекочевали из 16-ти битовых Windows, хотя они тождественны.
Сообщения . Посылка и передача сообщений
Ранее, на первых лекциях, мы рассматривали метод передачи сообщений, называемый “посылкой” сообщений (post). При использовании этого метода сообщение ставится в очередь приложения и позже извлекается из нее. Однако этот механизм не всегда удобен, так как не позволяет получить результата обработки сообщения, или дождаться его завершения. Точнее, позволяет, но очень громоздким способом.
Для решения этих задач вводится альтернативный механизм, называемый передачей сообщений. При этом сообщение в очередь не попадает и направляется непосредственно оконной функции. По сути его можно рассматривать как непосредственный вызов оконной функции с передачей ей указанных параметров. Это накладывает некоторые ограничения; так, например, нельзя передавать сообщение WM_QUIT - оно обязательно должно пройти через очередь сообщений, иные сообщения (скажем, клавиатуры) дополнительно обрабатываются в цикле обработки сообщений и их тоже надо посылать а не передавать и т.д.
Кроме того сложности возникают при использовании многопоточных приложений Win32 API - там принято, что сообщения, направленные окну, обязательно обрабатываются тем потоком, который это окно создал. Это существенно усложняет процесс передачи (не посылки) сообщений окну, созданному другим потоком - передающий сообщение поток помещает это сообщение в очередь принимающего потока с флагом ‘переданное сообщение ’ и приостанавливается до получения ответа. Принимающий поток, закончив обработку текущего сообщения, извлекает из очереди первыми сообщения, помеченные как переданные, обрабатывет их и после этого возобновляет работу пославшего потока. Однако при этом возможно зависание обеих потоков, если поток, принимающий сообщение, пытается передать вызывающему потоку подтверждение - тот находится в остановленном состоянии и не может обработать подтверждения, а принимающий в свою очередь останавливается, пока подверждение не будет обработано.
Для посылки и передачи сообщений могут применяться следующие функции:
BOOL PostMessage( hWnd, wMsg, wPar, lPar );
Посылает указанное сообщение окну (через очередь сообщений).
LONG SendMessage( hWnd, wMsg, wPar, lPar );
Передает сообщение окну (прямой вызов обработчика сообщений) и звращает управление в вызвавшую процедуру после обработки указанного сообщения. При этом она возвращает значение, возвращаемое оконной функцией. При использовании этой функции сообщение вообще не поступает в очередь приложения (кроме приложений Win32 API). То есть Вы можете воспользоваться этой функцией для обработки тех или иных сообщений до организации цикла обработки сообщений.
BOOL PostAppMessage( hTask, wMsg, wPar, lPar ); // Windows 3.x
BOOL PostAppMessage( dwProccessId, wMsg, wPar, lPar ); // Win32 API
BOOL PostThreadMessage( dwThreadId, wMsg, wPar, lPar ); // Win32 API
Посылает сообщение конкретной задаче. При этом в очередь соответствующего приложения помещается сообщение, имеющее нулевой хендл окна - получателя. Соответственно такое сообщение не диспетчеризуется никакому окну.
Хендл задачи hTask не является хендлом копии приложения. Вы можете использовать функцию GetCurrentTask для получения хендла задачи в среде Windows 3.x, а также функции GetCurrentThreadId и GetCurrentProcessId в Win32 API.
для получения этого хендла.
BOOL PostQuitMessage( wPar );
Посылает сообщение WM_QUIT с заданным параметром wPar вашему приложению. Сообщение WM_QUIT используется для завершения главного цикла обработки сообщений.
Типичные последовательности сообщений, получаемых окном .
Сейчас мы займемся изучением основных сообщений, используемых окном. При этом мы рассмотрим несколько типичных последовательностей сообщений, получаемых окном. Так, например, мы рассмотрим последовательность сообщений, получаемых окном при его создании. При этом надо считать, что приводимые сообщения в последовательности являются как бы “скелетом”, а реальная последовательность может иметь большее число сообщений, или некоторые могут отсутствовать. Это определяется характеристиками окна, его свойствами и выполняемой дополнительной обработкой сообщений. (Так, например, последовательности сообщений, получаемых “скрытыми” окнами или окнами в минимизированном состоянии могут существенно отличаться).
В рассматриваемых нами последовательностях сообщений большинство сообщений не проходят через очередь сообщений, а передаются непосредственно оконной процедуре какой-либо функцией. Именно логика выполнения этой функции и определяет последовательность получения сообщений. Кроме того, некоторые сообщения в этих цепочках являются как бы “вложенными” - то есть они порождаются при обработке какого-либо иного сообщения.
Инициализация окна
Для создания окна используется функция CreateWindow(). Во время ее выполнения окно получает несколько сообщений:
WM_GETMINMAXINFO 0 &MINMAXINFO
Информация о допустимых размерах окна; данные в структуре MINMAXINFO задаются ДО передачи сообщения, так что вы можете их не изменять, а только прочитать при необходимости. (Для получения данных Вы можете вместо обработки этого сообщения воспользоваться функцией GetWindowPlacement()).
WM_NCCREATE 0 &CREATESTRUCT
Созданиевнешней (non-client) областиокна. Обработка, предусмотренная процедурой DefWindowProc() инициализирует необходимые структуры и, в частности, выделяет пространство для хранения заголовка окна. Никакого рисования не выполняется. Возвращаемый процедурой 0 указывает на возникшую ошибку и окно не создается; не 0 указывает на успешное создание внешней области.
WM_NCCALCSIZE flag &NCCALCSIZE_PARAMS
Определение размера внутренней (client) части окна; кроме этого определяется часть окна, которая может быть скопирована без изменений при перемещении окна или изменении его размеров.
WM_CREATE 0 &CREATESTRUCT