В случае успешного выполнения функции CreateWindowExA требуемое окно будет создано, но пока это произойдет лишь внутри самой системы Windows — на экра- не это новое окно пока еще не отобразится. Для того чтобы созданное окно появи- лось на экране, необходимо применить еще одну функцию Win32 API — Show- WindowA. В качестве параметров этой функции передаются дескриптор hWnd окна, которое необходимо отобразить на экране, и константа, задающая начальный вид окна на экране. В зависимости от значения последнего параметра окно отобража- ется в стандартном виде, развернутым на весь экран или свернутым в значок. Описа- ние символических констант, задающих начальный вид окна на экране, содержит- ся во включаемом файле wiпusеr.h. Строки 127-131 нашего Windows-приложения задают отображение окна в стандартном виде. Если окно создано, то в него нужно что-то выводить — текст или графику. Здесь есть несколько тонких моментов, выяснение которых позволит нам «подняться сразу на несколько ступеней» в понимании принципов работы Windows. Поэтому задержимся немного. Тем более что в литературе этим моментам не всегда уделя- ется достаточно внимания — в лучшем случае десяток строк, большая часть кото- рых уходит на обсуждение функций и их параметров, а не на разъяснение сути происходящих при этом процессов. Ход наших рассуждений будем подкреплять практическими наблюдениями за работой приложения. Для этого можно исполь- зовать утилиты, которые позволят нам наблюдать за сообщениями, циркулирую- щими в системе, и вызовами функций API. В качестве таких программных средств можно использовать утилиты, входящие в комплект компиляторов для языка C/C++. Например, в состав Visual C++ входит утилита Spy++ (шпион), которая позволяет наблюдать за приложениями, находящимися в данный момент в систе- ме. Неплохие результаты для Windows-приложений дает дизассемблер W32Dasm, информацию о котором можно найти по адресу http://www.expage.com/page/ w32dasm. Если у вас нет ничего подобного под рукой, отчаиваться не стоит. Можно про- вести необходимые исследования опытным путем, просто меняя логику работы приложения. Суть этой методики состоит в комбинировании последовательности выполнения функций Win32 API, воспроизводящих звуковые файлы и выводя- щих текст на экран. При этом необходимо перемещать те или иные фрагменты программы друг относительно друга. Но это еще не все. Само воспроизведение относительно длительных звуковых файлов выполняется в определенном режи- ме. Обратите внимание на значение параметра fdwSound, который мы передаем функции Play S oundA. В нашем случае это комбинация двух констант, одна из кото- рых (SND_SYNC) означает, что функция не должна возвращать управление до тех пор, пока не закончится воспроизведение звукового файла. Если комбинировать вывод текстового сообщения и воспроизведение звукового файла, то это дает не- которую задержку, в ходе которой глаз может воспринять момент появления тек- стового сообщения на экране. Используем изложенную методику для изучения проблемы вывода информа- ции (не обязательно текста) на экран. В нашей программе мы будем эксперимен- тировать с выводом некоторого сообщения на экран, взяв за основу строки 189— 205. Выполним с ними несколько манипуляций и обсудим их результаты. Вырежем строки 189-205 из оконной процедуры WiпdоwРrос и вставим их в про- межутке между функциями CreateWindowExA и ShowWindowA. Перетранслируем за- ново исходный текст приложения, получим новый вариант исполняемого модуля и запустим его. Поведение нашей программы будет следующим: воспроизводится звуковой файл create.wav (что означает обработку асинхронного сообщения WM_CREATE оконной функцией), появляется пустое окно (отработала функция ShowWindowA), воспроизводится звуковой файл paint. wav(это означает, что в окон- ную функцию было передано сообщение WM_PAINT). На экране вы ничего не уви- дите, кроме пустого окна. Почему окно оказалось пустым несмотря на то, что мы в него поместили текстовое сообщение функцией ТехtОut? О причинах сложившей- ся ситуации можно привести некоторые соображения. ⅞` Работа функции ShowWindowA заключается лишь в отображении созданного функцией CreateWindowExA окна заданного класса и последующем заполнении фона этого окна цветом кисти, указанной в соответствующем поле структуры WNDCLASS. Ж Вывод в область окна становится возможным лишь после отображения окна на экране. И В системе Windows циркулируют два типа сообщений: синхронные и асин- хронные. Их различие — в приоритетах обработки. Функция ShowWindowA по- мещает в очередь сообщений приложения синхронное сообщение WM_PAINT. Все синхронные сообщения попадают в очередь сообщений приложения и обраба- тываются в порядке очередности. Это и послужило причиной того, что текст, выведенный в окно функцией TextOut, не был отображен в окне немедленно. В отличие от предыдущих двух доводов, данный вывод сделать довольно труд- но, не имея дополнительных средств исследования, о которых мы говорили ранее. Косвенно это можно выяснить, закомментировав в программе вызов функции UрdаtеWiпdоwА, основным назначением которой является посылка асинхронного сообщения WM_PAINT в оконную функцию. Асинхронные сооб- щения не ставятся в общую очередь приложения и сразу передаются в оконную функцию. Функция UpdateWindowA как раз и предназначена для таких ситуа- ций, в которых необходимо обновить содержимое окна. К этому вопросу, а так- же к синхронным и асинхронным сообщениям мы еще вернемся, поэтому при- мите пока все сказанное здесь на веру. Переместите теперь строки 189-205 (при этом именно переместите их, а не про- сто скопируйте) из функции WindowProc, разместив их сразу за вызовом функции ShowWindowA (перед UрdаtеWiпdоwА). Перетранслируйте заново исходный текст приложения, получите новый вариант исполняемого модуля и запустите его. По- ведение программы несколько изменилось. Файл create.wav воспроизведен, как обычно — после создания окна. Далее последовательно появились окно приложе- ния и долгожданное сообщение в его области. И лишь после этого был воспроиз- веден звуковой файл paint.wav. Поведение приложения для этого варианта разме- щения фрагментов кода приводит к новым выводам. и Функции Win32 API, выводящие что-либо в окно, должны размещаться после функций, реализующих действия по отображению окна. я Приложение должно самостоятельно следить за актуальностью содержимого своего окна. ® Весь вывод на экран должен производиться в оконной функции. Подтвердим правильность этих выводов следующими рассуждениями и экспе- риментами. Сверните и вновь разверните окно приложения. Вы увидите, что об- ласть окна вновь стала пустой, но при этом был воспроизведен звуковой файл create.wav. Исходя из того, что строки кода, воспроизводящие этот файл, находят- ся в оконной функции в том месте, где обрабатывается сообщение WМ_РАINТ, при- ходим к выводу — в очереди сообщений вновь оказалось это сообщение, и именно оно было обработано оконной функцией. Как сообщение WМ_РАINТ оказалось в очереди, если наше приложение на этот раз его туда не помещало, а сообщения WM_PAINT от ShowWindowA и UpdateWindowA к этому моменту уже обработаны и управ- ление передано циклу обработки сообщений? Ответ напрашивается сам собой: это делает сама система Windows, именно она рассылает в очереди сообщений всех приложений, окна которых отображены на экране, сообщение WM_PAINT. Но при этом Windows не берет на себя обязанность хранить содержимое этих окон. За актуальность содержимого окна должно отвечать само приложение. Сообщение WM_PAINT служит для приложения сигналом обновить либо заново восстановить содержимое своего окна. Следовательно, если мы хотим, чтобы результаты предыдущих выводов на экран были актуальны, необходимо после получения со- общения WM_PAINT перерисовать содержимое окна приложения. Последнее рас- суждение доказывает тезис о том, что весь вывод на экран должен производиться в оконной функции как реакция на поступление сообщения WM_PAINT. Эти рассуждения показывают роль сообщений (и не только WM_PAINT), цирку- лирующих в системе. Теперь, понимая всю их важность, можно приступить к рас- смотрению следующей важной части оконного Windows-приложения. При этом мы продолжим манипулировать фрагментами нашего программного кода (на этот раз звуковыми) для пояснения некоторых характерных моментов.