assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 89
Текст из файла (страница 89)
При этом необходимо перемещать те или иные фрагментыпрограммы друг относительно друга. Но это еще не все. Само воспроизведениеотносительно длительных звуковых файлов выполняется в определенном режиме. Обратите внимание на значение параметра fdwSound, который мы передаемфункции PlaySoundA. В нашем случае это комбинация двух констант, одна из которых (SND_SYNC) означает, что функция не должна возвращать управление до техпор, пока не закончится воспроизведение звукового файла. Если комбинироватьвывод текстового сообщения и воспроизведение звукового файла, то это дает некоторую задержку, в ходе которой глаз может воспринять момент появления текстового сообщения на экране.Используем изложенную методику для изучения проблемы вывода информации (не обязательно текста) на экран.
В'нашей программе мы будем экспериментировать с выводом некоторого сообщения на экран, взяв за основу строки 189205. Выполним с ними несколько манипуляций и обсудим их результаты.Вырежем строки 189-205 из оконной процедуры WindowProc и вставим их в промежутке между функциями CreateWindowExA и ShowWindowA. Перетранслируем заново исходный текст приложения, получим новый вариант исполняемого модуляи запустим его. Поведение нашей программы будет следующим: воспроизводитсязвуковой файл create.wav (что означает обработку асинхронного сообщенияWM_CREATE оконной функцией), появляется пустое окно (отработала функцияShowWindowA), воспроизводится звуковой файл paint.wav (это означает, что в оконную функцию было передано сообщение WM_PAINT).
На экране вы ничего не увидите, кроме пустого окна. Почему окно оказалось пустым несмотря на то, что мыв него поместили текстовое сообщение функцией TextOut? О причинах сложившейся ситуации можно привести некоторые соображения.' Работа функции ShowWindowA заключается лишь в отображении созданногофункцией CreateWindowExA окна заданного класса и последующем заполнениифона этого окна цветом кисти, указанной в соответствующем поле структурыWNDCLASS.Ж Вывод в область окна становится возможным лишь после отображения окна наэкране.И В системе Windows циркулируют два типа сообщений: синхронные и асинхронные. Их различие — в приоритетах обработки.
Функция ShowWindowA помещает в очередь сообщений приложения синхронное сообщение WM_PAINT. Всесинхронные сообщения попадают в очередь сообщений приложения и обрабатываются в порядке очередности. Это и послужило причиной того, что текст,выведенный в окно функцией TextOut, не был отображен в окне немедленно.В отличие от предыдущих двух доводов, данный вывод сделать довольно трудно, не имея дополнительных средств исследования, о которых мы говорилиранее. Косвенно это можно выяснить, закомментировав в программе вызовфункции UpdateWindowA, основным назначением которой является посылкаасинхронного сообщения WM_PAINT в оконную функцию.
Асинхронные сообщения не ставятся в общую очередь приложения и сразу передаются в оконнуюфункцию. Функция UpdateWindowA как раз и предназначена для таких ситуаций, в которых необходимо обновить содержимое окна. К этому вопросу, а так-394Глава 16. Создание Windows-приложений на ассемблереже к синхронным и асинхронным сообщениям мы еще вернемся, поэтому примите пока все сказанное здесь на веру.Переместите теперь строки 189-205 (при этом именно переместите их, а не просто скопируйте) из функции WindowProc, разместив их сразу за вызовом функцииShowWindowA (перед UpdateWindowA).
Перетранслируйте заново исходный текстприложения, получите новый вариант исполняемого модуля и запустите его. Поведение программы несколько изменилось. Файл create.wav воспроизведен, какобычно — после создания окна. Далее последовательно появились окно приложения и долгожданное сообщение в его области. И лишь после этого был воспроизведен звуковой файл paint.wav.
Поведение приложения для этого варианта размещения фрагментов кода приводит к новым выводам.и Функции Win32 API, выводящие что-либо в окно, должны размещаться послефункций, реализующих действия по отображению окна.ж Приложение должно самостоятельно следить за актуальностью содержимогосвоего окна.ж Весь вывод на экран должен производиться в оконной функции.Подтвердим правильность этих выводов следующими рассуждениями и экспериментами.
Сверните и вновь разверните окно приложения. Вы увидите, что область окна вновь стала пустой, но при этом был воспроизведен звуковой файлcreate.wav. Исходя из того, что строки кода, воспроизводящие этот файл, находятся в оконной функции в том месте, где обрабатывается сообщение WM_PAINT, приходим к выводу — в очереди сообщений вновь оказалось это сообщение, и именнооно было обработано оконной функцией. Как сообщение WM_PAINT оказалосьв очереди, если наше приложение на этот раз его туда не помещало, а сообщенияWM_PAINT от ShowWindowA и UpdateWindowA к этому моменту уже обработаны и управление передано циклу обработки сообщений? Ответ напрашивается сам собой: этоделает сама система Windows, именно она рассылает в очереди сообщений всехприложений, окна которых отображены на экране, сообщение WM_PAINT.
Но приэтом Windows не берет на себя обязанность хранить содержимое этих окон. Заактуальность содержимого окна должно отвечать само приложение. СообщениеWM_PAINT служит для приложения сигналом обновить либо заново восстановитьсодержимое своего окна. Следовательно, если мы хотим, чтобы результатыпредыдущих выводов на экран были актуальны, необходимо после получения сообщения WM_PAINT перерисовать содержимое окна приложения. Последнее рассуждение доказывает тезис о том, что весь вывод на экран должен производитьсяв оконной функции как реакция на поступление сообщения WM_PAINT.Эти рассуждения показывают роль сообщений (и не только WM_PAINT), циркулирующих в системе.
Теперь, понимая всю их важность, можно приступить к рассмотрению следующей важной части оконного Windows-приложения. При этоммы продолжим манипулировать фрагментами нашего программного кода (на этотраз звуковыми) для пояснения некоторых характерных моментов.Цикл обработки сообщенийСообщение в Win32 представляет собой объект особой структуры, формируемыйWindows. Формирование и доставка этого объекта в нужное место в системе по-Каркасное Windows-приложение на ассемблере395зволяют управлять работой как самой системы Windows, так и загруженныхWindows-приложений. Инициировать формирование сообщения могут несколько источников: пользователь, само приложение, система Windows, другие приложения.
Именно наличие механизма сообщений позволяет Windows реализоватьмногозадачность, которая при работе на одном процессоре является, конечно же,псевдомультизадачностью. Windows поддерживает очередь сообщений для каждого приложения. Запуск приложения автоматически подразумевает формирование для него собственной очереди сообщений, даже если это приложение и не будет ею пользоваться.
Последнее маловероятно, так как в этом случае у приложенияне окажется связи с внешним миром и оно превратится в «вещь в себе».Формат всех сообщений Windows одинаков и описывается структурой, шаблон которой содержится в файле winuser.h:/** Message structure*/typedef struct tagMSG {HWNDhwnd;UINTmessage;WPARAM wParam;LPARAM IParam;DWORD time;POINT pt;} MSG, *PMSG, NEAR *NPMSG, FAR "LPMSG;В этой структуре все типы данных вам знакомы, за исключением одного — POINT.Этот тип данных описан во включаемом файле windef .h и представляет собой структуру видаtypedef struct tagPOINT{ LONG x;LONG y;} POINT, «PPOINT, NEAR APPOINT, FAR «LPPOINT;На основе этого описания в файл windowsA.h помещено эквивалентное описание этой структуры в соответствии с синтаксисом ассемблера:POINTstrucxULONGОу ULONG ОendsMSG strucmeshwnd HWiND0mesUINT?wParam UINT?IParam UINT?timedd 0POINTstruc{}endsПоле meshwnd структуры MSG содержит значение дескриптора окна, которомупредназначено сообщение.
Это тот самый дескриптор, который возвращается функцией Create Win do wExA и, соответственно, однозначно идентифицирует окно в системе. Не забывайте, что приложение обычно имеет несколько окон, поэтому значение в поле meshwnd помогает приложению идентифицировать нужное окно.В поле mes Windows помещает 32-разрядную константу — идентификатор сообщения, однозначно идентифицирующий тип сообщения.
Для удобства все этиконстанты имеют символические имена, начинающиеся с префикса WM_ (WindowMessage). Посмотрите, каким образом они определены в файле winuser.h. Во включа-396Глава 16. Создание Windows-приложений на ассемблереемом файле для программ на ассемблере Win32.inc (и нашем варианте этого файла — windowsA.h) тоже содержатся некоторые из этих констант. Если в ходе работывам понадобятся отсутствующие константы, возьмите их из включаемых файловкомпилятора C/C++, исправив описание в соответствии с синтаксисом ассемблера.
В программе на языке C/C++ эти константы используются в оконной функции оператором switch для принятия решения о том, какая из его ветвей будетисполняться. В оконной функции каркасного Windows-приложения на ассемблере (строки 163-232) этот оператор моделируется командами условногои безусловного переходов (строки 168-174), а также командой стр, в качествевторого операнда которой и выступает константа, обозначающая определенный тип сообщения.Поля IParam и wParam предназначены для того, чтобы система Windows могларазместить в них дополнительную информацию о сообщении, необходимую дляего правильной обработки.
Эти поля, например, используются при обработке сообщений о выборе пунктов меню или о нажатии клавиш.В поле time Windows записывает информацию о времени, когда сообщение былопомещено в очередь сообщений.И наконец, поле POINT содержит координаты указателя мыши в момент помещения сообщения в очередь.Итак, представим, что в системе произошло какое-то событие, например, некоторому приложению необходимо перерисовать свое окно, в результате Чего система Windows сформировала сообщение WM_PAINT.
Данное сообщение попадаетв очередь сообщений приложения, создавшего окно. Для того чтобы приложениемогло обработать это (или любое другое) сообщение, ему необходимо сначала егообнаружить в очереди сообщений. С этой целью после отображения окна на экране программа «входит» в специальный цикл, называемый циклом обработки сообщений (строки 139-156). Выйти из этого цикла можно только по приходу сообщения WM_QUIT.
В этом случае функция GetMessageA возвращает нулевое значение,и команда условного перехода в строке 146 передает управление на конец циклаобработки сообщений. В случае прихода других сообщений функция GetMessageAвозвращает ненулевое значение, в результате чего и осуществляется вход непосредственно в тело цикла обработки сообщения. Функции GetMessageA передаетсянесколько параметров (строки 140-143):message — указатель на экземпляр структуры MSG (строка 42).
Во время работыфункция GetMessageA извлекает сообщение из очереди сообщений приложенияи на основе информации в нем инициализирует поля экземпляра структурыmessage. Таким образом, приложение получает полный доступ ко всей информации в сообщении, сформированном Windows;№ hWnd — в поле передается дескриптор окна, сообщения для которого должныбудут выбираться функцией GetMessageA.