Для эффективнойработысистемы и ее большогопокупательского
спроса недостаточно только того, чтобы аппаратура и программы обеспечивали
правильные результаты - не менее важным фактором является удобство
работы пользователя. Поэтому в настоящее время ни один программный продукт, лишенный
более менее удобного интерфейса взаимодействия пользователя с компьютером
и программ между собой, не может рассчитывать на успех. В мире разработано огромное
количество различных систем поддержки создания пользовательского интерфейса.
Наиболее прогрессивному, по нашему мнению, являются обьектноориетированная
система Turbo Vision фирмы Borland и операционная среда Windows фирмы Microsoft.
Рассмотрением возможностей системы Turbo Vision занималась в своей работе Фомичева
Т.Л., а в представленной работе производится изучение и обзор средств, входящих
в состав операционной среды Windows. Тот кто написал хотя бы одну коммерческую
программу, то знает, сколько времени и сил уходит на организацию меню и
выработку единого, непротиворечивого, интуитивно ясного и удобного пользовательского
интерфейса. Интерфейс, разработанный корпорацией Microsoft является одним
из лучших и стал своеобразным эталоном для подражания. В Microsoft Windows программисту
доступна вся мощь этого интерфейса - он избавляется от необходимости
организовывать меню, работу с клавиатурой и мышью (достаточно воспользоваться стандартными
средствами). Интерфейс с пользователем Windows является полным и цельным.
В нем решены не только проблемы организации меню, но и все общение с пользователем
организовано стандартными средствами. ИСТОРИЯ СОЗДАНИЯ MICROSOFT WINDOWS
Корпорация Microsoft объявила о начале разработки графической операционной
оболочки Windows 10 ноября 1983 года, хотя еще в конце 1982 года программисты
Microsoft начали создавать универсальный набор графических процедур, названный
Графическим Интерфейсом с Компьютером ( CGI ). Первоначально предполагалось, что
CGI как набор процедур будет поставляться с компиляторами Microsoft, позволяя
разработчикам программ выводить графику на самые различные типы принтеров. Программисты
могли бы использовать в своих программах функции CGI, которые затем переводились
бы в команды нужного типа принтера. Вскоре после начала работ над CGI
корпорация Microsoft развернула работы по созданию графической операционной
среды для компьютеров с MS-DOS. Создание такой оболочки было инспирировано неожиданным
интересом пользователей IBM совместимых компьютеров к объявлению корпорацией
VISICorp о начале работ над многооконной операционнной оболочкой VisiOn.
Таким образом, старая добрая конкуренция сделала свое дело - в феврале 1983 года
стало ясно, что Microsoft создаст свою собственную оболочку Windows. Хотя многие
особенности и свойства Windows кардинально изменились в последующем, некоторые
положения были ясны с самого начала. Windows должна быть многозадачной, т.е.
должна позволять запускать несколько программ одновременно. Windows должна работать
со всеми типами дисплеев и принтеров. И поскольку пользователю очень трудно
отказаться от привычных программных средств, Windows должна позволять запускать
приложения MS-DOS. Последняя цель настолько оказалась трудной в реализации,
что задержала весь проект на многие месяцы. Задача оказалось не из простых. Типичной
машиной был компьютер со сравнительно медленным процессором 8088 и оперативной
памятью 64Kb. Если учесть, что MS-DOS накладывает принципиальное ограничение
по оперативной памити в 640Kb и, в отличие от компьютеров Macintosh, не обеспечивает
программноаппаратную поддержку графики, разработка многозадачной графической
операционной оболочки грозила вырасти в неразрешимую задачу. Однако Microsoft
развернула работы над Windows полным ходом. К осени 1983 года разработкой
Windows было занято уже 15 высококвалифицированных программистов, привлеченных
к проекту из различных филиалов Microsoft. Многие фирмы командировали своих
специалистов для одновременного участия в проекте. Когда работы над CGI перешли
в фазу тестирования, это не был уже самостоятельный продукт. CGI был переменован
в GDI (the Graphics Device Interface - "Интерфейс с графическими Устройствами")
и стал частью Windows, включив в себя процедуры работы не только с принтером,
но и с дисплеем. Для этого в CGI были добавлены функции, обеспечивающие поддержку
типографско-издательских особенностей в работе с текстами и процедуры манипулирования
графическими объектами. При презентации первого варианта Windows
было обещано, что коммерческая продажа начнется в мае 1984. Весной 1984 года дата
начала продаж была отодвинута на ноябрь. В ноябре эта дата была перенесена на
июнь 1985 года. Однако коробки с Windows появились в магазинах только 18 ноября
1985 года.Несколько факторов привели к стользначительнымзадержкам. Однако
главную роль сыграло нежелание Microsoftвыходить на рынок с сырым продуктом. В феврале
1984 года главакорпорации Microsoft Билл Гейтс ( Bill Gates ) провел семинар,на
котором представил Software Development Kit ( SDK ), пакетдля написания
приложений под Windows, продемонстрировав на немвозможности, предлагаемые программисту
под Windows. SDK произвел хорошее впечатление и к июню 1984 года было
продано почти 100 копий. Начав работать под Windows, программисты присылали в Microsoft
свои замечания, заставляя разработчиков еще и еще отшлифовывать Windows,
облегчаянаписание приложений. Был заменен язык, на котором создавалсяWindows
( сначала это был Microsoft Pascal, затем Lattice C и,наконец, Microsoft C Compiler
). Ориентация на Microsoft CCompiler также была одной из причин задержки
работ надпроектом, потому, что сам компилятор не был готовым продуктоми постоянно
совершенствовался. Однако, несмотря на то, что в ноябре 1985 года Windows все
же вышел на прилавки магазинов, в течение двух лет ( с 1985 по 1987 год ) Windows
не оказал большого влияния на рынок программного обеспечения и не стал альтернативой
MS-DOS, как надеялся Microsoft. Большое число пользователей ( 51% )
покупали Windows не ради созданных для него приложений (которых было очень мало
по сравнению с обычными программами под MS-DOS ) или графического интерфейса,
а для того, чтобы иметь возможность быстро переключаться с одного DOS приложения
на другое. С 1987 года ситуация начала меняться. Начали появляться мощные и известные
приложения, переписанные для работы под Windows. Сейчас можно назвать
такие продукты как Page Maker под Windows, очень мощная электронная таблица Excel,
Windows Graph, Word for Windows и многие другие. С выходом третей версии Windows
стало ясно, что Windows не просто завоюет прочное место на рынке программного
обеспечения, но станет основой стратегической политики Microsoft в создании
программного обеспечения. Windows 3.0 произвел настоящий фурор, предлагая совершенно
потрясающую графику и новые, неожиданные возможности. В июле 1990 года
"PC Magazine" поместил статью о новой версии Windows 3.0, в которой отмечалось,
что Microsoft Windows превратился в блестящую многозадачную операционную систему,
которой еще пытается стать OS/2. Как и все программные продукты Microsoft,
первые версии Windows не оправдывали надежд несмотря на то, что выходили со значительными
задержками, но в своем последнем варианте оставляют конкурентов далеко
позади. ОБЗОР ОСНОВНЫХ ПРИНЦИПОВ ОРГАНИЗАЦИИ ИНТЕРФЕЙСА В WINDOWS Для понимания
принципов организации интерфейса Windows необходимо иметь представление об
основных его элементах, на которых построено выполнение программ и взаимодействие
программы и пользователя. Весь интерфейс Windows основывается на трех китах:-
аппаратно-независимая графика;- стандартный оконно-ориентированный интерфейс;-
взаимодействие приложений с системой Windows и между собой посредством передачи
сообщений; Данные элементы системы Windows самым тесным образом связаны между
собой, вместе образуют целостную систему и отдельное рассмотрение каждого из
них в отрыве от других не имеет смысла. Перечисленные выше элементы системы Windows
ниже будут рассмотрены более подробно, а пока вкратце остановимся на том,
что они из себя представляют. Аппаратно-независимый графический интерфейс (GDI)
Любая программа для Windows может выполнять вывод на любое устройство с помощью
одного и того же набора вызываемых подпрограмм. Причем для Windows приложения
все устройства выглядят одинаково и программисту не нужно забодится об управлении
конкретным устройством на низком уровне. Каждое устройство имеет свой драйвер,
отвечающий за фактическое выполнение графического вывода. Для устройств, которым
при этом необходима помощь, GDI обеспечивает программную эмуляцию, использующую
для реализации функций высокого уровня средства низкого уровня этого устройства.
При выводе информации на экран дисплея GDI обеспечивает оконно-ориентированную
графику. Это означает, что каждое окно рассматривается как отдельная область
прорисовки. Когда программа выполняет в окне прорисовку, то координаты по
умолчанию устанавливаются так, что точка начала координат (0,0) находится в верхнем
левом углу клиентной области окна. Кроме того, рисунки автоматически отсекаются
по границам окна. Подобные механизм защиты работает двусторонне, то есть
ни вы не можете нарисовать что-либо вне своего окна, ни другая программа нарисовать
что-то в вашем окне. Стандартный оконно-ориентированный интерфейс Система
Windows имеет встроенную поддержку ряда обьектов пользовательского интерфейса:
окон, пиктограмм, меню, блоков диалога и т.п.Окно Окно представляетсобойсамуюважнуючастьпользовательского
интерфейса. Оно играет ключевую роль. Для программиста
окно служит для организации прочих обьектов пользовательского интерфейса
и направляет прохождение сообщений в системе, окно обеспечивает область экрана
для связи с пользователем. Окно - это самостоятельно существующий обьект, параметры
которого описаны в специальных структурах данных, а поведение функцией
окна. Каждое окно принадлежит классу окон. Класс окон - это шаблон, по которому
реализуются реальные окна. С каждым классом окон и, следовательно, с каждым окном
связан специальный тип подпрограммы, называемый процедурой окна. Задача процедуры
окна состоит в обработке поступающих окну сообщений. Каждое приложение располагается
в своем собственном окне и имеет по крайней мере хотя бы одно окно
- главное окно приложения. Из приложения Windows непосредственно нельзя осуществить
вывод на экран, так как экран является разделяемым ресурсом, а средством
его разделения являются окна. Таким образом, прежде чем отобразить что-либо на
экране, нужно создать окно, и только в окне можно осуществить вывод.Пиктограммы
Пиктограмма представляетсобой небольшой рисунок,который служит для пользователя
напоминанием о чем-либо иобозначают команду, программу или некоторые данные.
Меню Меню представляет собой список команд и функций программы. Имеется пять типов
меню:- системные,- горизонтальные,- выпадающие,- вложенные,- всплывающие.
Системные меню обеспечивают стандартный набор операций, которые могут быть выполнены
с окном (перемещение, изменение размеров, закрытие, переключение на другую
задачу и т.д.). Это меню обязательно находится в главном меню каждого приложения.
Горизонтальное меню фиксировано привязывается к верху окна. Выпадающие меню
появляются при выборе соответствующих пунктов горизонтального меню. Вложенные
меню появляются при выборе соответствующих пунктов выпадающих меню. Прикладная
программа может вкладыватьодно меню в другое до любого уровня вложенности. Всплывающие
меню могут располагаться в произвольной позиции в окне и фактически в
любой позиции на экране дисплея.Полосы прокрутки Используются в тех случаях, когда
обьект данных больше размеров окна. Полосы прокрутки бывают вертикальными и
горизонтальными. Они позволяют пользователю управлять отображением больших обьемов
данных и иметь к ним доступ.Существует ограничение на обьем данных в скроллинге.
Обьем данных не может превышать 64 Кбайт.Курсоры Курсор представляет собой
битовый образ, перемещаемый по экрану в ответ на перемещения мыши или другого
координатного устройства. Программа может изменить формукурсора, чтобы отобразить
некоторое изменение в системе.Каретка Каретка - это небольшая битовая матрица,
которая является отметкой фокуса ввода с клавиатуры. Окно, управляющее вводом
с клавиатуры может создать каретку, чтобы сообщить пользователю об этот факте.
Пользовательский интерфейс Windows поддерживает только одну каретку на экране.Блоки
диалога Блок диалога - это стандартный способ приема программой ввода
от пользователя. Типичный пример блока диалога - это блок диалога для открытия
файла. Блок диалога представляет собой окно, содержащее внутри себя отдельные окна,
которые либо выводят некоторую информацию, либо позволяют принять ввод от
пользователя. Каждое их этих окон называется элементом управления диалогом. Система
имеет шесть предопределенных классов окон, на базе которых создаются элементы
управления блоками диалога:- кнопки;- комбинированные блоки;- элементы управления
редактированием;- блоки списков;- полосы прокрутки;- статические элементы.
Более полное описание обьектов интерфейса представлено ниже. Механизм сообщений
В системе Windows любое приложение строится как совокупность обработчиков различных
событий, которые происходят совершенно независимо друг от друга. Каждое
событие генерирует, сообщение, которое передаются всем приложениям, для которых
оно может представлять интерес. Приложение представляет собой 16-битовое значение
без знака, которому для удобства присваивается символьная константа. Все
сообщения имеют единый формат и являются единственным средством связи приложения
с операционной оболочкой и с другими приложениями. Некоторые сообщения могут
в свою очередь порождать другие сообщения. При поступлении сообщения о произошедшем
событии, это сообщение помещается в системную очередь Windows. Системная очередь
в Windows одна. После этого сообщения из системной очереди распределяются
между приложениями. Для каждого приложения Windows организует и поддерживает
отдельную очередь, куда пересылаются все сообщения для этого приложения.Обработку
очереди приложения осуществляет само приложение. Если сообщение поступило например
от устройств ввода, таких как мышь или клавиатура, то для определения адресата
сообщения используется понятие "фокус ввода". Так как пользователь в каждый
момент времени может работать только с одним приложением. Таким образом, говорят,
что приложение, в которое попадают сообщения от клавиатуры в момент ввода,
имеет фокус ввода, поэтому все сообщения от устройств ввода информации поступают
из системной очереди в очередь приложения, имеющего фокус ввода в данный момент.Для
обработкипоступающих сообщений в программеорганизуется цикл сообщений,
который создается при присоздании окна приложения. Цикл сообщений извлекает
сообщенияиз очереди и передает их функции управления соответствующимокном приложения,
причем не напрямую а через Window. О функцииокна приложений пойдет речь
позже. Все стандартные сообщения, определенные в системе Windows можно разделить
на несколько групп:- аппаратные (входные данные от мыши и клавиатуры);- об организации
окна (уведомление, требование действия, запрос);- оборганизации интерфейса
пользователя (меню,указатель мыши, линейка прокрутки, блоки диалога, MDI);-
о завершении (закрытие прикладной программы или системы);- частные (элементы
управления блоком диалога: редактор кнопка, блок списка, комбо-блок);- уведомление
о системном ресурсе (изменение цвета, шрифты, буферизация печати, режимы
работы устройств);- о совместном использовании данных (буфер вырезанного изображения
и динамический обмен данными DDE);- внутренние системные (недокументированные
сообщения). Ниже будут более подробно рассмотрены перечисленные классы сообщений
в контексте их применения. Особое внимание будет уделено сообщениям по взаимодействию
между приложениямии совместному использованию данных. ИНТЕРФЕЙС ГРАФИЧЕСКИХ
УСТРОЙСТВ (GDI) В данном разделе рассматриваются вопросы связанные с
созданием графического вывода, обсуждаются различные типы графического вывода,
поддерживаемых интерфейсом графических устройств (GDI). GDI представляет собой
библиотеку графического вывода Windows. GDI обеспечивает графический вывод на
экран дисплея и на устройства для получения твердых копий, например, принтеры и
плоттеры. GDI отвечает за создание отображения каждой линии, буквы или графического
знака, выводимого программой для Windows. Сама Windows использует GDI при
подборке элементов, составляющих пользовательский интерфейс, - окон, пиктограмм,
меню, блоков диалога и т.д. Устройства GDI Интерфейс графических устройств позволяет
выполнять графический вывод на различные устройства. Для того, чтобы GDI
работал с конкретным устройством, необходим специальный элемент программного
обеспечения - драйвер устройства, который преобразует запросы графического вывода
в конкретные действия для рисования на конкретном устройстве. Помимо этого,
драйвер устройства представляет GDI набор флагов, которые сообщают, какими графическими
возможностями обладает данное устройство. Существует пять наборов таких
флагов: для кривых линий, для прямых, многоугольников, битовых образов и текстов,
которые сообщают GDI, когда можно направить устройству непосредственно запрос,
а когда такой запрос надо предварительно преобразовать в последовательность
запросов низкого уровня. Это зависит то возможностей конкретного устройства.
Помимо физических устройств GDI поддерживает логические устройства, или псевдоустройства.
Псевдоустройства служат для хранения изображений. В отличие то физических
устройств, которые выводят изображения на определенной аппаратной базе,
псевдоустройства позволяют "перехватить" образ изображения в оперативной памяти
или на диске. GDI поддерживает два типа псевдоустройств: битовые образы и метафайлы.
Битовые образы имеют прямоугольную форму и хранят изображения в памяти в
таком виде, в каком графические образы хранятся дисплейным адаптером, и обеспечивают
быстрое получение копии картинки. Битовые образы используются и для хранения
образов, которые нужно быстро выводить на экран, например, пиктограммы, курсоры
и т.д.Метафайлы создаются средствами записи-воспроизведения GDI. Сточкизрениярасходуемойпамяти
метафайлыпредпочтительнее, чем битовые образы, однако
работа снимипроисходит медленнее. Обычно в метафайлах хранятся крупныеизображения.
Логические обьекты графики GDI Одним из средств достижения аппаратной независимости
GDI является использование логических обьектов графики. Такой обьект
описывает, каким образом должен выполняться вывод, это высокоуровневый аппаратно-независимый
запрос. GDI поддерживает следующие логические обьекты графики:- перья
(для рисования линий);- кисти (для закрашивания областей);- шрифты (для вывода
текстов);- логические цвета (описывающие цвета вывода). После создания логического
обьекта он может быть использован в отношении любого устройства, при этом
драйвер каждого устройства по своему интерпретирует логический обьект способом,
соответствующий возможностям устройства. Контекст устройства Контекст устройства представляетсобой
некотороемножество атрибутов графического вывода, в которое
входит одноперо для рисования линий, одна кисть для закрашивания областейи
один шрифт для вывода текстов, которые можно изменить влюбой момент. Вместе
взятые, атрибуты графического вывода даютполный контроль над тем, как выглядит
и где выполняетсяграфический вывод программы. Каждый контекст устройства включает
в себя 20 атрибутов графического вывода, которые приведены ниже (в скобках приведено
значение по умолчанию):- Цвет фона (белый);- Режим фона (OPAQUE);- Логический
номер кисти (белая кисть);- Начало координат кисти (0,0);- Логический номер
области прорисовки (вся поверхность);- Логический номер цветовой палитры (палитра
по умолчанию);- Текущая позиция пера (0,0);- Режим графического вывода
(R2_COPYPEN);- Логический номер шрифта (системный шрифт);- Межсимвольный интервал
(0);- Режим отбражения (MM_TEXT);- Логический номер пера (черное перо);- Режим
закрашивания многоугольников (альтернативный);- Режим растяжения (черный по
белому);- Выравнивание границ текста (по левому и верхнему краям);- Цвет текста
(черный для текста и кистей с монохромным шаблоном закрашивания);- Выравнивание
строк текста (0,0);- Протяженность окна данного экрана (1,1);- Начало координат
окна данного экрана (0,0);- Протяженность окна экрана (1,1);- Начало координат
окна экрана (0,0). Контекст устройства связывает программу с конкретной поверхностью
рисования. Такое соединение является логическим, а не физическим. Чтобы
избежать конфликтов, связанных с совместным использованием устройств, программа
получает у контекста устройства "пропуск" к устройству. Работа системы пропусков
зависит от типа устройства. На устройствах получения твердых копий это делается
путем буферизации ввода, а на видеоустройствах - путем выделения так называемой
области прорисовки, вне границ которой программа рисовать не может. Основные
атрибуты контекста устройства Для рисовании линий самым важным атрибутом контекста
устройства является перо, определяющее, как будет выглядеть линию: ее
цвет, ширина и стиль (или шаблон, например, сплошная линия, пунктир и т.п.) и представляющее
из себя запрос к устройству на рисование линии определенного вида.
При рисовании линий также используется атрибут - режим графического вывода, в
котором можно задать логическую операцию, чтобы применить ее при выводе между
новым и старым пикселями. Для закрашивания областей используется атрибут кисть,
определяющий как будет выглядеть закрашиваемая область и характеризующийся тремя
характеристиками: стилем, цветом и шаблоном. Размер кисти составляет 8Х8 пикселей.
При изображении текста ключевым атрибутом является шрифт. Шрифт - совокупность
шаблонов для вывода текста. GDI распознает два вида шрифтов: логические
и физические.Логический шрифтописывает текст стандартным независящим от внешних
устройства. Он выбирается по описанию, содержащемуся в логическом шрифте и может
быть аппаратно реализован. Для задания атрибута контекста устройства используется
функция SelectObject, описанная следующим образом:HANDLE FAR PASCAL SelectObject(HDC,
HANDLE); Здесь первый параметр - логический номер контекста устройства,
а второй - логический номер значения атрибута. Для того, чтобы получить
логический номер требуемого значения атрибута контекста, используется функция GetStockObject.
Ее прототип:HANDLE FAR PASCAL GetStockObject(int);Параметром являетсязначениеатрибутаконтекстаустройства,
обычно для удобства задаваемое в
виде наборасимволов. Программист может использовать либо уже заданные значения атрибутов,
либо создавать свои новые. Перерисовка области и изображение пикселей
Из-за того, что Windows не накладывает ограничений на размеры и расположение окон
приложений, могут возникнуть ситуации, что окно одного приложения перекроет
окно другого приложения, поэтому при переключении между приложениями необходимо
перерисовыть поврежденные области окна. Для этой цели используется подпрограмма
BeginPaint. При получении сообщения WM_PAINT, говорящее о необходимости перерисовки
окна из изменения его размеров или восстановления поврежденной области,
подпрограмма BeginPaint получает контекст устройства и определяет область, которую
надо перерисовать.Подпрограмма BeginPaint принимаетдвапараметра:логический
номер окна и указатель на структуру данныхPAINTSTRUCT, Она возвращает логический
номер контекста устройства, необходимый для рисования пикселя. Прототип подпрограммы
имеет вид:HDC FAR PASCAL BeginPaint(HWND, LPPAINTSTRUCT);Структура PAINTSTRUCT
определена так:typedef struct tagPAINTSTRUCTHDChdc; BOOLfErase;RECTrcPaint;BOOLfRestore;BOOLfIncUpdate;BYTErgbReserved[16];
PAINTSTRUCT;hdc -
логический номер контекста устройства;fErase - флаг, задающий необходимость стирания
окна; rcPaint - описывает прямоугольник, ограничивающийповрежденную область;
fRestore, fIncUpdate и rgbReserved предназначены для внутреннего использования
Windows.Для отображенияпикселя используется подпрограммаSetPixel. Ее прототип:DWORD
FAR PASCAL SetPixel( HDC, int, int, DWORD); HDC - логический контекст
устройства; следующие два параметра - координаты пикселя; последний параметр
- цвет. После завершения перерисовки, программа вызывает функцию EndPaint, чтобы
вернуть контекст устройства дисплея Менеджеру Окон и сообщить, что окно восстановлено.
Когда тот получает контекст устройства, он восстанавливает все его атрибуты
по умолчанию, и контекст устройства готов к передаче информации любой программе,
которой понадобится нарисовать окно. Подпрограмма EndPaint имеет прототип:void
FAR PASCAL EndPaint(HWND, LPPAINTSTRUCT); Рисование линий Каждая линия
имеет начальную и конечную точку, и GDI рисует линию так, начальная точка включается
в линию, а конечная исключается из линии. GDI имеет 4 подпрограммы для рисования
линий: MoveTo, LineTo, PolyLine и Arc. Подпрограмма MoveTo помещает пару
координат XY в атрибут контекста устройства, который называется текущей позицией.
Подпрограмма имеет прототип:DWORD FAR PASCAL MoveTo( HDC, int x1, int y1
); Подпрограмма LineTo берет начальную точку из атрибута текущей позиции и рисует
линию до конечной точки, передаваемой как параметр. После этого она устанавливает
новое значение атрибута текущей позиции. Подпрограмма имеет прототип:BOOL
FAR PASCAL LineTo( HDC, int x1, int y1 ); Подпрограмма Polyline позволяет нарисовать
ломанную линию, но для ее работы необходимо предварительно создать массив
координат точек. Подпрограмма имеет прототип:BOOL FAR PASCAL Polyline( HDC, LPPOINT
points, int num ); points - указатель на массив координат, котором координаты
оси абсцисс и оси ординат чередуются; num - число пар координат в массиве.
Подпрограмма Arc позволяет нарисовать дуги эллипса. Передаваемые параметры определяют
прямоугольник, ограничивающий фигуру, если бы она была полной, начальную
точку и конечную. Подпрограмма имеет прототип:BOL FAR PASCAL Arc( HDC,int,int,int,int,int,int,int,int);
Рисование закрашенных фигур Для рисования закрашенных
фигур существует семьразличных функций. Функция Polygon соединяет расположенные
последовательно точки с помощью текущего установленного в контексте устройства
пера. Функция определена так:BOOL FAR PASCAL Polygon(HDC, LPPOINT, int);HDC
- логический номер контекста устройства; LPPOINT - указатель на массив координат,
соединяемых граничных точек;Третий параметр - число соединяемых точек. Функция
PolyPolygon позволяет нарисовать за один вызов несколько многоугольников и
определена так:BOOL FAR PASCAL PolyPolygon(HDC, LPPOINT, LPINT, int);HDC - логический
номер контекста устройства; LPPOINT - указатель на массив координат, соединяемых
граничных точек всех создаваемых многоугольников; LPINT - указатель на
массив типа int. Элементы массива задают число точек в каждом многоугольнике*
Последний параметр задает количество точек в массиве LPINT, то есть количество
многоугольников. Для рисования закрашенного эллипса используется функция Ellipse.
Она определяется так:BOOL FAR PASCAL Ellipse(HDC, int, int, int, int);HDC -
логический номер контекста устройства;Остальные параметрыопределяют координатыограничивающего
прямоугольника. Функция Chord используется для рисования частичной
дуги, концы которой соединены сегментом линии. Для этого также используется
ограничивающий прямоугольник. Определение функции следующее:BOOL FAR PASCAL Chord(HDC,int,
int,int, int,int, int,int, int);HDC - логический номер контекста
устройства;Следующие четыре параметры определяют координатыограничивающего прямоугольника.
Далее указываются координаты начальной и конечной точки сегмента линии.
Функция Pie аналогична функции Chord, только рисует не хорду, а сектор эллипса.
Она определена следующим образом:BOOL FAR PASCAL Pie(HDC,int, int,int, int,int,
int,int, int);HDC - логический номер контекста устройства;Следующие четыре
параметры определяют координатыограничивающего прямоугольника. Далее указываются
координаты начальной и конечной точки сектора.Для рисования прямоугольника
используется функцияRectangle.Ее прототип:BOOL FAR PASCAL Rectangle(HDC, int,
int, int, int);HDC - логический номер контекста устройства;Остальные параметрыопределяют координатыпрямоугольника.
Если требуется нарисовать прямоугольник с
закругленными краями, то имеется функция RoundRect. Она определена та:BOOL FAR
PASCAL RoundRect(HDC,int, int,int, int,int, int);HDC - логический номер контекста
устройства;Следующие четыре параметры определяют координатыпрямоугольника.
Последние два параметра задают ширину и высоту ограничивающего прямоугольника для
эллипса, используемого при скруглении угла. Вывод текста Для вывода текста имеется
пять основных функций. Функция TextOut предназначена для вывода одной строки.
Она определена следующим образом:BOOL FAR PASCAL TextOut(HDC, int, int, LPSTR,
int);HDC - логический номер контекста устройства; Следующие два параметры
определяют координаты точки привязки выводимой стоки текста.LPSTR - указатель на
выводимую символьную строку.Последний параметр - число символов в строке текста.
Более мощный вариант функции TextOut представляет собой функция ExtTextOut.
Она позволяет управлять интервалом между строками и вырезкойBOOL FAR PASCAL ExtTextOut(
HDC,int, int,WORD wOptions,LPRECT lpRect,LPSTR lpString,WORD nCount,LPINTlpDx
);HDC - логический номер контекста устройства; Следующие два параметры
определяют координаты точки привязки выводимой стоки текста. wOptions - флаг,
принимающий значение 0, ETO_CLIPPED, ETO_OPAQUE и ETO_CLIPPED|ETO_OPAQUE, позволяющий
устанавливать прямоугольные области вырезки и при выводе текста затирать
фон.lpRect - указатель на структуру прямоугольника;lpString - указатель на выводимую
символьную строку.nCount - число символов в строке текста. lpDx -указатель
на массив значений интервалов междусимволами. Функция TabbedTextOut при выводе
текста распространяет знаки табуляции до позиций табуляции. Это обеспечивает
удобный способ выравнивания столбцов данных. Прототип функции:LONG FAR PASCAL
TabbedTextOut(HDC,int, int,LPSTR, int, LPINT, int);HDC - логический номер контекста
устройства; Следующие два параметры определяют координаты точки привязки
выводимой стоки текста.LPSTR - указатель на выводимую символьную строку.Следующий
параметр - число символов в строке текста. LPINT - указатель на массив позиций
табуляции; Последний параметр - число элементов массиве позиций табуляции.
Функция DrawText обеспечивает некоторую возможность форматирования и переход в автоматическом
режиме на новую строчку при большом количестве строк текста. Ее прототип:int
FAR PASCAL DrawText(HDC, LPSTR, int, LPRECT, WORD);HDC - логический
номер контекста устройства;LPSTR - указатель на выводимую символьную строку.Следующий
параметр - число символов в строке текста. LPRECT - указатель на структуру
прямоугольника,определяющего позицию вывода и границы для форматирования. Последний
параметр определяет режим форматирования.Для отображениязаблокированныхпунктов
меню изаблокированных элементов управления блоками диалога МенеджерОкон
использует функцию GrayString. ЭЛЕМЕНТЫ ОКОННОГО ИНТЕРФЕЙСА Окна Windows Главное
окно приложения Каждое приложение располагается в своем собственном окне
и имеет по крайней мере хотя бы одно окно - главное окно приложения. Из приложения
Windows непосредственно нельзя осуществить вывод на экран, так как экран является
разделяемым ресурсом, а средством его разделения являются окна. Таким образом,
прежде чем отобразить что-либо на экране, нужно создать окно, и только в
окне можно осуществить вывод. Функция главного окна приложения выполняет в программе
ту же роль, что функция main() программы на Си для MS-DOS. При создании
окна функция библиотеки SDK выполняет специальные действия начальной подготовки
в DOS, не явно осуществляемых функцией main(). Поэтому приложение не содержит
функции main(), роль которой выполняет функция WinMain(), получающая управление
в начальный момент загрузки приложения. Функция WinMain() выполняет следующие
основные действия:- регистрациякласса окна приложения и другиеинициализации;-
создание основного окна приложения и, возможно, других, подчиненных окон;- запуск
цикла обработки сообщений, помещаемых в очередь приложения;- завершение работы
приложения при извлечении из очереди сообщения WM_QUIT. Прототип функции WinMain
выглядит так:int PASCAL WinMain(HANDLE instance,// дескриптор предыдущей
копииHANDLE prevInstance, // предыдущая копияLPSTR cmdLine,// указатель на командную
строкуintcmdShow // флаг "окно открыто/закрыто");instance - однозначноопределяеткаждуюкопиюприложения,
если приложение запущено несколько раз. prevInstance
- определяет копию данного приложения, которая была последней активной
копией. Если этот параметр равен 0, то других копий приложения, исполняемых в
данный момент не существует. cmdLine - дальний указатель на командную строку, оканчивающуюся
нулем. Он позволяет приложениям получать данные через командную строку.
cmdShow - определяет, как приложение первоначально отображать на экране:
пиктограммы (cmdShow = SW_SHOWMINNOACTIVE) или в виде открытого окна (cmdShow
= SW_SHOWNORMAL). Константы SW_SHOWMINNOACTIVE и SW_SHOWNORMAL определены во включаемом
файле windows.h. Регистрация класса окна Любое окно принадлежит к одному
из существующих классов. Класс окна должен быть создан до того, как окно будет
отображено на экране. Класс окна определяет общие свойства всех окон данного
класса, например: форму курсора при перемещении его в области окна или имя меню,
определенного для окон этого класса. Характеристики окна задаются при регистрации
класса окна (в структуре класса окна) и при создании окна. Наиболее общие
характеристики окон задаются при регистрации класса окна. Окна, создаваемые при
помощи функции CreateWindiw, должны иметь зарегистрированный ранее класс окон.
Есть несколько стандартных классов окон с заранее определенными свойствами. Однако,
как правило, каждое приложение регистрирует свой собственный класс с тем,
- указатель на функцию поддержки окна. Краткое описание этой функции смотри
в следующем разделе. style - содержит набор флагов, определяющих свойства окна.
По умолчанию присваивается NULL.hBrBackground - определяет цвет фона окна. hCursor
- определяет курсор, используемый в данном окне по умолчанию. hIcon - определяет
пиктограмму (icon), которая будет отображаться при переводе окна в неактивное
состояние. lpszMenuName - указатель на имя меню окна, определенное в файле
ресурсов. cbClsExtra - определяет число байт, которое необходимо дополнительно
запросить у Windows под эту структуру. Этот обьем памяти будет зарезервирован
в конце структуры для всех окон данного класса. clWndExtra - определяет число
байт, которое необходимо дополнительно запросить у Windows для размещения всех
структур, создаваемых совместно с данным классом. После определения полей структуры
WNDCLASS необходимо зарегистрировать класс при помощи функции RegisterClass.BOOL
FAR PASCAL RegisterClass( LPWNDCLASS winClass ); Если регистрация класса
прошла успешно, то возвращаемое значение TRUE, в противном случае - FALSE. При
регистрации класса окна Windows копирует структуру, описывающую класс окна, в
системную область, чтобы другим копиям приложения уже не надо было ее регистрировать.
Функция окна приложения Функция окна приложения занимается тем, что обрабатывает
все сообщения для окон данного класса. Это функция всегдавызывается неявно
Windows при поступлении сообщений в окно, закоторым оно закреплено. Функция
окна имеет вид:long far PASCAL WndProc ( HWND hwnd,WORD msg,WORD wParam,LONG
lParam ); hwnd - логический номер окна, идентифицирующий окно, связанное с приложением;msg
- идентификатор приложения; wParam и lParam определяют дополнительную
информацию и зависят от типа сообщения.Для облегченияработыпрограммистасуществуетспециальная
функция обработки сообщений DefWindowProc с темиже параметрами,
которая производит стандартную обработку всехсообщений. Кроме того она играет
ключевую роль в формированииинформационных потоков сообщений Windows, и ее
окон). Когда показывается, скрывается или уничтожается, все порожденные им
окна разделяют его судьбу Дескриптор меню позволяет определить меню, которое будет
изображаться в окне. Дескриптор копии позволяет идентифицировать владельца
окна, то есть указывает Windows, какой именно экземпляр программы создал окно.
В результате Windows получает возможность правильно установить регистр сегмента
данных дляинициализации окна. Последний параметр функции позволяет передать указатель
на данные в оконную процедуру. Указатель передается с самым первым сообщением
WM_CREATE, что необходимо для обеспечения данных при инициализации окна.
В случае успешного создания окна функция CreateWindow возвращает индекс окна.
Отображение и обновление окна Окно не отображается на экране сразу после создания;
для отображения окна используется функция ShowWindow. Ее прототип:BOOL FAR
PASCAL ShowWindow( HWND wnd, int cmdShow );wnd - дескриптор отображаемого окна;
cmdShow - определяет, как окно первоначально будет отображаться на экране:SW_SHOWNORMAL-
обычное окно;SW_SHOWMINIMIZED - минимизированное в виде пиктограммы;
SW_SHOWMAXIMIZED - максимизорованное на весь экран; Для обновления окна используется
функция UpdateWindow. Ее прототип выглядит так:void FAR PASCAL UpdateWindow(
HWND wnd ); Типы окна Тип окна задается 32-битовым целым числом, которое
представляет собой комбинацию битовых флагов, определяющих различные свойства окна.
WS_OVERLAPPED - перекрывающееся окно. Перекрывающиеся окна - это основной
наиболее универсальный тип окон Windows. Главное окно приложения обычно имеет такой
вид. WS_POPUP - вспомогательные окна. Они используются чаще всего для отображения
окон диалога. Вот некоторые свойства вспомогательных окон:- если такое
окно имеет родительское окно, то всегда отображаются поверх всех окон на экране,
даже когда пользователь делает активным другое окно;- вспомогательные окна не
имеют заголовка и часто должны иметь фиксированный размер. WS_CHILD - дочернее
окно. Окна такого типа создаются, если у приложения есть главное (а значит и перекрывающее
окно) и связаны некоторыми характеристиками с тем окном из которого
были вызваны. Все органы управления также являются дочерними окнами. Вот некоторые
их свойства: - дочерние окна никогда не отображаются вне своего родительского
окна ни в раскрытом виде, ни в виде пиктограммы; - координаты дочерних окон
отчитываются от верхнего левого угла рабочей области окна-родителя и при перемещении
последнего, дочерние окна перемещаются вместе с ним;- дочернее окно никогда
не может стать активным окном. WS_MINIMIZE - создаваемое окно будет отображено
в виде пиктограммы. WS_VISIBLE - Окно становится видимым сразу после создания.
Используется для диалоговых окон.WS_DISABLED - создается неактивное окно.WS_CLIPSIBLINGS
-исключение областей, занимаемыхдругими дочерними окнами из изменяемой
области дочернего окна.Используется только для дочерних окон.WS_CLIPCHILDREN
- исключение областей,занимаемыхдругими дочерними окнами при изменении
рабочей областиродительского окна. Используется только для родительских окон. WS_MAXIMIZE
- создаваемое окно будет отображено в максимально возможном виде. WS_CAPTION
- окно имеет рамку и заголовок, а следовательно пользователь может перемещать
его при помощи мыши. WS_BORDER - окно имеет широкую рамку без заголовка.
Используется при создании диалоговых окон.WS_DLGFRAME - окно имеет тонкую рамку
без заголовка.WS_VSCROLL - окно имеет вертикальную полосу просмотра.WS_HSCROLL
- окно имеет горизонтальную полосу просмотра.WS_SYSMENU - окно имеет системное
меню. WS_THICKFRAME - создаваемое окно имеет рамку существенно заметной толщины.WS_MINIMIZEBOX
- окно имеет кнопку минимизации.WS_MAXIMIZEBOX - окно имеет кнопку
максимизации. Построение меню Для создания меню нужно проделать:1. Задатьструктуруменювфайле
ресурсов,последовательно определив пункты меню в виде текстовых
строк.2. Каждому пункту меню поставить в соответствие уникальный идентификатор.3.
Указать имя меню в структуре класса окна. Определение менюОпределение
меню в файле ресурсов должно иметь вид:MenuName MENU [опции загрузки][опции
памяти]BEGINMENUITEM "Item1" IDM_Item1 [, опции]MENUITEM "Item2" IDM_Item3 [, опции]...POPUP"Item3"
[, опции]BEGINMENUITEM "Item3-1" IDM_Item3-1 [, опции] MENUITEM
"Item3-2" IDM_Item3-2 [, опции] ...ENDEND MenuName - имя ресурса меню для
обращения из подпрограммы. Опции загрузки определяет как следует поступить с
ресурсом при загрузке приложения на выполнение - сразу загрузить или при неоходимости.
Опции памяти определяют, как Windows должна обращаться с сегментом памяти,
куда загружается ресурс. Пункты меню определяются между словами BEGIN и END.
Они могут быть двух видов: MENUITEM и POPUP. Пункт типа MENUITEM является конечным
пунктом меню. При выборе этого пункта функции окна сообщения передается сообщение
WM_COMMAND с идентификатором пункта меню в качестве параметра. Пункт типа
POPUP является заголовком подменю. Опции пункта меню могут комбинироваться.
В качестве опций пункта меню могут быть следующие значения: GRAYED - пункт меню
не активен. Текст пункта меню отображается в сером цвете. INACTIVE - пункт меню
не активен. Текст пункта меню отображается также как и в других пунктах. MENUBREAK
- этот и следующий за ним пункты меню отображаются в новом столбце (если
указан для главного меню, то в новой строке). MENUBARBREAK - этот и следующий
за ним пункты меню отображаются в новом столбце (если указан для главного меню,
то в новой строке); предыдущий и новый столбец разделяются вертикальной чертой.
CHECKED - пункт меню помечен галочкой, помещенной слева от него. Не действует
для пунктов главного меню. SEPARATOR - определяет разделитель, который выделяет
в группы связанные списки меню. HELP - пункт меню выравнивается по правой стороне
меню. Обьекты диалога Обьекты диалога, в состав которых входят кнопки, комбинированные
блоки, элементы управления редактированием, блоки списков, полосы
прокрутки, статические элементы, являются с точки зрения Windows обычными дочерними
окнами. Взаимодействие между родительским окном (окном диалога) и обьектами
диалога осуществляется посредством сообщений. Когда пользователь производит какое-либо
действие с обьектом диалога, функции окна родителя передается сообщение
WM_COMMAND, в качестве параметра wParam которого передается индекс обьекта диалога,
а в качестве параметра lParam - специальная дополнительная информация.Для
того, чтобы сконструировать обьект диалога нужно:1. Зарегистрировать класс окна
диалога. 2. Создать дочернее окно функцией CreateWindow, указав зарегистрированный
класс окна. 3. В функции окна обьекта диалога определить дескриптор дочернего
окна при помощи функции GetParent. 4. По тому или иному действию пользователя
уведомлять родительское окно соответствующими сообщениями при помощи функции
SendMessage. Для обьектов диалога как дочерних окон не требуется регистрировать
класс окна - в Windows определены стандартные классы окон - обьектов диалога:
"button", "edit", "scrollbar", "listbox" и пр. При использовании стандартных
классов Windows для создания обьекта диалога нужно вызвать только функцию CreateWindow.Рассмотрим
основные обьекты диалога. Кнопки и переключатели Кнопка "Button"
обычно используется для осуществления каких - либо немедленных действий,
без переключения или включения/выключения каких-либо опций.Переключатель "И" ("CheckBox") используется какпереключатель
опций вкл/выкл. Будучи соединенными
в группупереключатели реализуют логику "И". Переключатель "ИЛИ" ("RadioButton")
используется как переключатель опций вкл/выкл. Будучи соединенными в группу переключатели
реализуют логику "ИЛИ". Вокруг этих трех основных типов имеются некоторые
вариации. Ниже приводится описание стандартных классов кнопоки переключателей.BS_PUSHBUTTON
- определяет кнопку с жирной рамкой. BS_DEFPUSHBUTTON - определяет
кнопку с жирной рамкой. Обычно используется для определения действия по
умолчанию.BS_CHECKBOX -определяет квадратик, имеющий двасостояния: отмеченное
(перечеркнут крестиком) и не отмеченное(квадратик пуст). В момент отметки рамка
квадрата выделяетсяжирной линией. BS_AUTOCHECKBOX - тоже, что предыдущий, только
состояние кнопки при отметке отслеживается автоматически. BS_RADIOBUTTON - определяет
круглую кнопку, которая может быть нажата (внутри окружности жирная точка)
и отпущена. Справа от кнопки может быть любой поясняющий текст. BS_AUTORADIOBUTTON
- тоже, что и предыдущее, только при отметке кнопки пользователем ранее
сделанная отметка автоматически снимается. BS_3STATE - тоже, что и BS_CHECKBOX,
только добавлено состояние, что действие или свойство не действительно (обозначается
штриховкой кнопки). BS_AUTO3STATE - тоже, что и предыдущее, только смена
состояний поддерживается автоматически. BS_GROUPBOX - определяет рамку, охватывающую
другие обьекты диалога.BS_OWNERDRAW -обьектдиалога,определяемыйпользователем,
который полностью берет на себя работу с ним.BS_LEFTTEXT -используетсядлявыравниванияпояснительного
текста по левой стороне кнопок.Кнопки посылают
функцииокнародителя сообщениеWM_COMMAND,в качестве параметра lParam указывается
дескрипотор органауправления и код нотификации, служащий для определения
то а горизонтального просмотра;EN_VSCROLL-нажата клавиша горизонтального
просмотра. Окно список Окно список "listbox" представляет собой прямоугольник,
внутри которого находится листаемый список из текстовых строк. Пользователь
может выделить строки списка при помощи курсора. Окно-список используется
для просмотра и выбора элементов древовидного списка. Приведем типы окна списка.
LBS_NOTIFY - родительское окно получает информацию о любом действии пользователя
в списке;LBS_SORT - строки сортируются по алфавиту; LBS_MULTIPLESEL - множественный
выбор с переключениемвыбора для каждой строки; LBS_OWNERDRAWFIXED - отображение
содержимого списка возлагается на функцию родительского окна, все элементы
списка могут иметь разную высоту; LBS_OWNERDRAWVARIABLE - отображение содержимого
списка возлагается на функцию родительского окна, все элементы списка
могут иметь разную высоту; LBS_HASSTRINGS - определяет пользовательское окно-список
с произвольными строками; LBS_USETABSTOPS - символы табуляции заменяются
на пробелы;LBS_MULTICOLUMN - определяет многостолбцовый список; LBS_EXTENDEDSEL
- в окне-списке можно делатьмножественный выбор с помощью мыши и клавиши Shift.
В качестве параметров сообщения WM_COMMAND передаются идентификатор дочернего
окна-редактора, индекс дочернего окна и код сообщения. Код сообщения может быть:LBN_ERRSPACE
- списку не хватает памяти;LBN_SELCHANGE - изменен выбор элемента;LBN_DBLCLK-
выбор двойным нажатием кнопки мыши. Комбинированный списокКомбинированный
списокпредставляет срокуредактирования, к которой привешено окно-список.
Стандартныетипы обьекта: CBS_SIMPLE - список отображается все время, и текущее
выделение отслеживается среди элементов списка; CBS_DROPDOWN - то же, что
и предыдущее, но список не отображается, пока пользователь на нажмет на левую кнопку
мыши; CBS_DROPDOWNLIST - то же, но строка редактирования заменяется на статическую
текстовую строку, ее нельзя редактировать; CBS_OWNERDRAWFIXED - элементы
списка отрисовываются пользователем, их высота одинакова; CBS_OWNERDRAWVARIABLE
- элементы списка отрисовываются пользователем, их высота одинакова; CBS_AUTOHSCROLL
- горизонтальная прокрутка в строке редактирования;CBS_SORT - сортировка
автоматическая элементов списка. ОБМЕН ДАННЫМИ МЕЖДУ ПРИЛОЖЕНИЯМИ Средства
обмена данными между приложениями Одним из средств, обеспечивающим программнуюсовместимость,
является механизм обмена данными междуразличнми приложениями. Специальный
почтовый ящик (clipboard)Windows позволяет пользователю переносить информацию
из одного приложения в другое, не заботясь об ее форматах и представлении.В
отличиеот профессиональных операциональныхоперационных систем, где механизм
обмена данными между программами доступен только программисту, в Windows это
делается очень просто и наглядно для пользователя. Механизм обмена данных между
приложениями - жизненно важное свойство многозадачной среды. И в настоящее
времяпроизводители программного обеспечения пришли уже к выводу,что для переноса
данных из одного приложения в другоепочтового ящика уже недостаточно. Появился
новый, болееуниверсальный механизм - OLE ( Object Linking and Embedding )- Встроенная
объектная связь, который позволяет переносить из одного приложения в другое
разнородные данные. Например, с помощью этого механизма данные, подготовленные
в системе сетевого планирования Time Line for Windows ( Symantec ), можно
переносить в текстовый процессор Just Write ( Symantec ), а затем, скажем, в генератор
приложений Object Vision (Borland). Правда, это уже нестандартное средство
Microsoft Windows, но тем не менее реализация OLE стала возможной именно в
Windows. Кроме механизма почтового ящика, предназначенного, в основном, для пользователя,
программисту в Windows доступны специальные средства обмена данными
между приложениями. Программным путем можно установить прямую связь между задачами,
например, принимая данные из последовательного порта, автоматически помещать
их, скажем, в ячейки электронной таблицы Excel, средствами которой можно тут
же отображать сложные зависимости в виде графиков или осуществлять их обработку
в реальном режиме времени (этот механизм носит название динамического обмена
данными - Dynamic Data Exchange, DDE ).Остановимсяболееподробнонамеханизмединамического
обмена данными между приложениями. Динамический обмен между приложениями
Мы обсудим основные идеи работы DDE и использование библиотеки DDE в своих
приложениях в следующих разделах:- Основные термины- Несколько слов о DDEML-
Взаимодействие Клиента и Сервера- Транзакции, функция обратного вызова DDE( CallBack
function )- Service, item и topic имена- Системный режим- Инициализация-
Основное назначение и работа функции обратного вызова- Обработка строк- Service
имена. Регистрация, фильтр- Диалог между приложениями- Простой диалог- Сложный
диалог- Обмен данными между приложениями- Классы транзакций- Определение наличия
ошибок при динамическом обмене данными. Основные термины Клиентское приложение
DDE - приложение, которому необходимо установить диалог с сервером и получить
данные от сервера в процессе диалога. DDE-диалог - взаимосвязь между клиентским
и серверным приложениями. Сервер-приложение - DDE приложение, которое передает
данные клиенту в процессе диалога. DDE-Транзакция -обмен сообщениями или данными
между клиентом и сервером.Itemимя - строка,идентифицирующаянекотороемножество
данных, которое сервер в состоянии передатьклиенту в процессе диалога.Serviceимя
- строка,генерируемаясервером ииспользуемая клиентом для установления
диалога. Строковый указатель - двойное слово, генерируемое операционной системой,
идентифицирующее строку, передающуюся в процессе динамического обмена данными.Topicимя
- строка, которая идентифицирует типданных,необходимыхклиентскомуприложениюпридинамическом
обмене данных.Фильтртранзакции - флаг,который
препятствуетпередаченежелательныхтипов транзакций в функциюобратного вызова.
Несколько слов о DDEML В Microsoft Windows динамический обмен данных является
формой связи, которая использует общие области памяти для обмена данными между
приложениями. Приложение может использовать DDE в некоторый момент времени для
передачи и получения новых данных от сервера. Механизм DDE схож с механизмом почтового
ящика, который является частью операционной системы WINDOWS. Существует
лишь незначительная разница в том, что почтовый ящик, в большинстве случае, используется
как буфер временного хранения информации. DDE может быть инициализирован
пользователем и в большинстве случаев продолжать работать без его вмешательства.
Библиотека DDEML обеспечивает пользователя набором средств, которые упрощают
использование механизма DDE в WINDOWS приложениях. Вместо того, чтобы обрабатывать,
получать и передавать DDE сообщения напрямую, приложения используют
функции DDEML библиотеки. Библиотека DDEML также обеспечивает работу со строками
и разделяемыми данными, генерируемыми DDE приложениями. Вместо того, чтобы использовать
указатели на общие области памяти, DDE приложения создают и обмениваются
строковыми указателями, которые идентифицируют строки и данные. Уже существующие
приложения, использующие протокол DDE, основанный на сообщениях полностью
совместимы с теми, которые используют библиотеку DDEML. Вот почему приложение,
использующее DDE-протокол могут установить диалог и выполнять транзакции с приложениями,
использующими библиотеку DDEML. Взаимосвязь между клиентом и сервером.
DDE возникает всегда между клиентским приложением и серверным. Клиентское приложение
инициализирует обмен данными путем установления диалога с сервером и
передачи транзакции. Транзакция необходима для данных и обслуживания. Сервер отвечает
на транзакцию и обеспечивает клиента данными. Сервер может иметь сразу несколько
клиентов в одно и тоже время, в свою очередь, клиент может получать данные
сразу от нескольких серверов. Некоторое приложение одновременно может быть
и клиентом и сервером. В добавок к вышесказанному, клиент и сервер могут оборвать
диалог в любое удобное для них время. Транзакции, функция обратного вызова
DDE( CallBack function ) DDEML информирует приложение об активности DDE путем передачи
транзакции в функцию обратного вызова данного приложения. DDE транзакция
схожа с обыкновенным сообщением - это именованная константа, сопровождаемая другими
параметрами, которые содержат дополнительную информацию о текущей транзакции.
DDEML передает транзакцию в функцию обратного вызова приложения, которая
выполняет некоторое действие согласно типу и виду транзакции. Например, когда клиентское
приложение пытается установить дилог с сервером, клиент вызывает функцию
DdeConnect. Это означает, что DDEML должна послать транзакцию XTYP_CONNECT
в функцию обратного вызова сервера. Функция обратного вызова может позволять или
не позволять установку диалога, возвращая TRUE или FALSE DDEML. Вспомогательные
имена и другие названия DDE сервер использует три зарезервированных типа имен,
расположенных иерархично: service, topic item - уникально идентифицируют некоторое
множество данных, которое сервер может передать клиенту в процессе диалога.
Service имя - это строка, которую генерирует сервер в те промежутки времени,
в которые клиент может установить диалог с сервером. Topic имя - это строка,
которая идентифицирует логический контекст данных. Для сервера, который манипулирует
файлами, topic имена это просто названияфайлов; для других серверов - это
специфические именаконкретногоприложения.Клиентобязательнодолженуказывать
topic имя вместе с service именем, когда онхочет установить диалог с сервером.
Item имя - это строка, которая идентифицирует некоторое множество данных, которое
сервер может передать клиенту в процессе транзакции. Например, item имя может
идентифицировать ЦЕЛОЕ ( int, integer ), СТРОКУ ( string, char * ), несколько
параграфов текста, или BITMAP образ.Всевышеуказанныеименапозволяютклиентуустановить
диалог с сервером и получить от него данные. Системный режим Системный
режим работы обеспечивает клиента всей необходимой информцией о сервере. Для
того, чтобы определить, какие серверы доступны в данный момент времени, а также
какой информацией они могут обеспечить клиента, последний, находясь в начальном
режиме работы, должен установить имя устройства, равное NULL. Такой шаблон диалога
максимально увеличивает эффективность работы, а также работу с сервером в
системном режиме. Сервер, в свою очередь, должен поддерживать нижеописанные item
имена, а также другие, часто используемые клиентом: SZDDESYS ITEM TOPICS - список
item имен, с которыми может работать сервер в данный момент времени. Этот
список может изменяться время от времени. SZDDESYS ITEM SYSITEMS - список item
имен, с которыми может работать сервер в системном режиме. SZDDDESYS ITEM STATUS
- запросить текущий статус сервера. Обычно, данный запрос поддерживается только
в формате CF_TEXT и содержит строку типа Готов/Занят.SZDDEITEMITEMLIST-список
item имен,поддерживаемых сервером в несистемном режиме работы. Этотсписок
может меняться время от времени.SZDDESYSITEMFORMATS-списокстрок,представляющий
собой список всех форматов почтового ящика,поддерживаемых сервером в данном
диалоге. Например,CF_TEXT формат представлен строкой TEXT. Инициализация Перед
вызовом любой функции DDEML, приложение должно вызвать функцию DdeInitialize.
Эта функция получает идентификатор копии данного приложения, регистрирует функцию
обратного вызова приложения посредством DDEML и указывает флаг фильтра транзакции
для функции обратного вызова. КаждоеприложениеилиDLL должно содержатьидентификатор
своей копии, например, в параметре idInst.Он необходим любой функции
DDEML. Это очень легко поддается объяснению: назначение DDEML - поддержка
механизма DDE в приложениях, несколько копий которых может быть запущено в данный
момент времени. Однако приложение НЕ МОЖЕТ использовать более одной копии DDEML.Фильтртранзакцииоптимизируетэффективностьсистемы
путем предотвращения передачи
нежелательных типов транзакций в функцию обратного вызова. Приложение устанавливает
фильтр транзакции при вызове функции DdeInitialze. Приложение должно
указать флаг фильтра транзакции для каждого типа транзакции, которые не будут
обрабатываться в функции обратного вызова. Однако любое приложение может изменить
фильтр транзакции путем дополнительного вызова функции DdeInitialize. Приведем
пример инициализации DDE-диалога.DWORD idInst = 0;HINSTAINCE hInst;DdeInitialize(
idIns,//Копия приложения( PFNCALLBACK ) DdeCallback, // Адрес CallBack
функции CBF_FAIL_EXECUTES | // Фильтр XTYPE_EXECUTE CBF_SKIP_ALLNOTIFICATIONS,
0 );// Фильтр NOTIFICATIONSКаждоеприложениедолжновызыватьфункциюDdeUninitialize,когдаонобольшене
собираетсяиспользовать DDEML. Эта функция прекращает
текущий диалог и освобождает ресурсы DDEML, предоставленные системой для установления
диалога. Основное назначение и работа функции обратного вызоваПриложение,котороеиспользуетDDEML,
должносодержать функцию обратного вызова, которая
обрабатывает события, полученные приложением. DDEML уведомляет приложение о таких
событиях путем посылки транзакций в функцию обратного вызова данного приложения.Взависимостиотфлага
фильтра транзакции,сформированного при вызове функции
DdeInitialize, функция обратного вызова получает отсортированные транзакции вне
зависимости от того, является ли данное приложение клиентом, сервером или тем
и другим одновременно. Следующий пример демонстрирует наиболее типичное использование
функции обратного вызова.HDDEDATA CALLBACK DdeCallback( uType, uFmt, hconv,
hsz1, hsz2, hdata, dwData1, dwData2 )UINT uType;//Тип транзакцииUINT uFmt;//Формат
почтого ящикаHCONV hconv;//Идентификатор диалогаHSZ hsz1;//Идентификатор
строки #1HSZ hsz2;//Идентификатор строки #2 HDDEDATA hdata; // Идентификатор
глобального объекта памяти DWORD dwData1; // Данные текущей транзакции
#1DWORD dwData2;// Данные текущей транзакции #2switch (uType)case XTYP_REGISTER:case
XTYP_UNREGISTER:. . .return (HDDEDATA) NULL;case XTYP_ADVDATA:. . .return
(HDDEDATA) DDE_FACK;case XTYP_XACT_COMPLETE:. . .return (HDDEDATA) NULL;case
XTYP_DISCONNECT:. . .return (HDDEDATA) NULL;default:return (HDDEDATA) NULL;ПараметрuTypeидентифицируеттиппосланнойтранзакции
в функцию обратного вызова
при помощи DDEML. Значения оставшихся параметров зависят от типов транзакции.
Типы транзакций будут обсуждены нами в разделе "Обработка Транзакций". Обработка
строкДлятого, чтобы работать в режиме диалога,большинство DDEML функций требуют
наличия доступа к строкам. Например, клиент должен в явном виде указывать
service и topic имена, когда приложение вызывает функцию DdeConnect для установления
диалога с сервером. Приложение указывает строку путем передачи ее идентификатора
в соответствующее место (также как и в случае указателя на DDEML функцию).
Идентификатор строки - это двойное слово, определяемое системой.Приложениеможет
получить идентификатор строкипутемвызовасоответствующейфункцииDdeCreateStringHandle.
Эта функция регистрирует строку в системе и возвращает ее идентификатор
приложению. Следующий пример получает идентификатор строки для строк System
topic и Service-name.HSZ hszServName;HSZ hszSysTopic;. . .hszServName = DdeCreateStringHandle(idInst,//
Копия приложения "MyServer",// Строка для регистрацииCP_WINANSI);//
Кодовая страница Windows ANSIhszSysTopic = DdeCreateStringHandle(idInst,//
Копия приложенияSZDDESYS_TOPIC, // Строка для регистрации CP_WINANSI);
// Кодовая страница Windows ANSI. . .ПараметрidInstсодержитидентификатор,возвращенный
функцией DdeInitialize. Функция обратного вызова получает
один или более строковых идентификаторов при обработке большинства DDE-транзакций.
Например, сервер получает два идентификатора строк в процессе транзакции типа
XTYP_REQUEST: один идентификатор - это строка, описывающая topic имя, а другой
- item.Приложениеможетполучатьдлинустроки,соответствующую идентификатору
строки и копировать этустроку в некоторый буфер, предварительно зарезервированныйприложением.
Все вышеуказанные действия можно проделать при помощи вызова функции
DdeQueryString, как продемонстрировано в следующем примере:DWORD idInst;DWORD
cb;HSZ hszServ;PSTR pszServName;. . .cb = DdeQueryString(idInst, hszServ,
(LPSTR) NULL, 0,CP_WINANSI) + 1;pszServName = (PSTR) LocalAlloc(LPTR, (WORD) cb);DdeQueryString(idInst,
hszServ, pszServName, cb, CP_WINANSI);. . .Итак,функцияDdeQueryStringсоздает
строку,используястроковый идентификатор, а затем функцияDdeCreateStringHandle
создает строковый идентификатор из строки. Следует отметить,
что два идентификатора НЕ СУЩЕСТВУЮТ в одно и тоже время.DWORD idInst;DWORD
cb;HSZ hszInst, hszNew;PSZ pszInst;. . .DdeQueryString(idInst, hszInst, pszInst,
cb, CP_WINANSI); hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI);
// hszNew != hszInst !. . .Привозвращениинекоторогозначения функциейобратноговызоваидентификаторстрокипортится.
Вприложении можно сохранить идентификатор
при помощи функции DdeKeepStringHandle и использовать этот идентификатор
после вызова функции CallBack.КогдаприложениевызываетфункциюDdeCreateStringHandle
и указывает строку, которая уже существует, система помещает эту строку
в таблицу и генерирует некоторый идентификатор, необходимый для быстрого и корректного
доступа к этой строке. Система также сохраняет количество использования
каждой строки в этой же таблице. Если приложение пытается определить строку,
которая уже существует в таблице, система просто увеличивает ее количество использования,
а при вызове функции DdeFreeStringHandle, соответственно уменьшает
на 1. Строка удаляется из таблицы, когда ее количество использования равно 0. Service
имена. Регистрация, фильтр. DDEML позволяет регистрировать service имена
для сервера и не посылать транзакцию вида XTYP-CONNECT для неподдрерживаемых service
имен в функцию обратного вызова. Остановимся на обсуждении этого вопроса
более подробно. При регистрации service имен в DDEML, сервер информирует другие
DDE-приложения в системе о том, что текущий сервер доступен для обмена данными.
Сервер регистрирует service имя путем вызова функции DdeNameService и указывает
идентификатор строки, связанной с именем. При получении вышеуказанных данных
DDEML посылает транзакцию вида XTYP-REGISTER в функцию обратного вызова каждого
DDEML-приложения в системе (за исключением только тех, которые указали флаг
фильтрации GBF_SKIP_REGISTRATION в функции DdeInitialize).ТранзакцияXTYP_REGISTERпередаетдваидентификатора
строк в функцию обратного вызова: первый изних
указывает на основное service имя, а второй - настроку, содержащую системную информацию.
Обычно клиент использует основное service имя в списке всех доступных
серверов так, что конечный пользователь может выбрать необходимый ему сервер, перемещаясь
по этому списку. Также клиент использует системную информацию для непосредственного
установления диалога с сервером. Сервер может использовать функцию
DdeNameServise для того, чтобы сбросить регистрацию service имени. Это оэначает,
что DDEML необходимо послать транзакцию вида XTYP_UNREGISTER в оставшиеся
DDE-приложения с информацией о том, что они больше не смогут использовать данное
service имя для установления диалога. Сервер должен вызывать функцию DdeNameServise
для регистрации его service имени сразу после вызова функции DdeInitialize.
Сервер должен сбрасывать свое service имя сразу после вызова функции DdeUninitialize.
Помимо регистрации service имени функция DdeNameService поэволяет включать
или выключать серверу ее собственный фильтр service имени. Когда сервер
выключает фильтр, DDEML посылает транзакцию вида XTYP_CONNECT в функцию обратного
вызова сервера вне зависимости от того совпадают ли вызываемое service имя
с зарегистрированным или нет при вызыве клиентом функции DdeConnect. Когда сервер
включает фильтр, транзакция вида XTYP_CONNECT посылается лишь в том случае,
когда вызываемое service имя совпадает с зарегистрированным. По умолчанию, фильтр
включен лишь тогда, когда приложение вызывает функцию DdeInitialize. Это необходимо
для предотвращения генерации транзакции XTYP_CONNECT до того как созданы
необходимые идентификаторы строк. Сервер может выключить фильтр путем установки
флага DNS_FILTEROFF при вызове функции DdeNameService. Флаг DNS_FILTERON включает
фильтр. Диалог между приложениямиДиалогмеждуклиентомисерверомвсегдаустанавливается
по требованию клиента. Когда диалогустановлен, оба партнера получают
идентификатор, которыйописываетданныйдиалог.Партнерыиспользуютэтотидентификатор
вбольшинстве функций DDEML для посылки транзакций и для ихобработки.
Клиенту может потребоваться диалог как с однимсервером, так и с несколькими.
Рассмотрим подробно как приложение устанавливает диалог и получает информацию о
уже существующих каналах связи. Простой Диалог Клиентское приложение устанавливает
простой диалог с сервером путем вызова функции DdeConnect и определяет идентификаторы
строк, которые содержат всю необходимую информацию о service имени текущего
сервера и интересущем клиента в данный момент topic имени. DDEML отвечает
на вызов этой функции посылкой соответствующей транзакции XTYP_CONNECT в функцию
обратного вызова каждого доступного в данный момент времени сервера, зарегистрированное
имя которого совпадает с именем, переданным при помощи функции DdeConnect
при условии, что сервер не отключал фильтр service имени вызовом функции
DdeServiceName.СерверможеттакжеустановитьфильтрнаXTYP_CONNECT транзакцию
заданием соответствующего флага CBF_FAIL_CONNECTIONS при вызове функции DdeInitialize.
В процессе обработки транзакции типа XTYP_CONNECT DDEML передает полученные
от клиента service и topic имена серверу. Сервер должен проверить эти имена
и возвратитьTRUE, если он в состоянии работать с такими именами, и FALSE в
противном случае. Если ни один из существующих серверов не отвечает на CONNECT-запрос
клиента, функция DDeConnect возвращает ему NULL с информацией о том, что
в данный момент времени НЕ возможно установить диалог. Однако, если сервер возвратил
TRUE, то диалог был успешно установлен и клиент получает идентификатор диалога-
двойное слово, посредством которого и ведется обмен данными с сервером.ЗатемсерверполучаеттранзакциювидаXTYP_CONNECT_CONFIRM
(в случае, если он НЕ
описывал флаг фильтра CBF_FAIL_CONFIRMS при вызове соответствующей функции).Внижеприведенном
примере производится попыткаустановить диалог с сервером, который
в состоянии работать с service именем 'My Server' в системном режиме. Считаем,
что параметры hszSysTopic и hszServName уже предварительно созданы нами ранее.HCONV
hConv;HWND hwndParent;HSZ hszServName;HSZ hszSysTopic;. . .hConv = DdeConnect(idInst,//
Копия приложенияhszServName,// Идентификатор service-имениhandle
hszSysTopic, // Идентификатор system-topic-имени (PCONVCONTEXT) NULL); //
Используем контекст по умолчаниюif( hConv == NULL )MessageBox( hwndParent, "MyServer
НЕ доступен!",(LPSTR) NULL, MB_OK );return FALSE;. . . В этом примере функция
DdeConnect заставляет DDEML посылать транзакцию вида XTYP_CONNECT в функцию
обратного вызова сервера MyServer. А теперь приведем пример функции обратного
вызова сервера, который обрабатывает транзакцию XTYP_CONNECT и сравнивает свое
зарегистрированное имя с именем, полученным от клиента. Как уже было отмечено
ранее, если они совпадают, то сервер в состоянии установить диалог с клиентом.#define
CTOPICS 5HSZ hsz1;// Идентификатор строки,полученный от DDEML.HSZ ahszTopics[CTOPICS];
// Массив поддреживаемых topic имен int i; // Счетчик цикла ..
// Для обработки транзакций используем стандартную ANSI C . // конструкцию switch
--> case --> default..case XTYP_CONNECT:for (i = 0; i AM , 1 --> PM TIME;HDDEDATA
EXPENTRY DdeCallback(uType, uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2)UINT
uType;UINT uFmt;HCONV hconv;HSZ hsz1;HSZ hsz2;HDDEDATA hdata;DWORD dwData1;DWORD
dwData2;CHAR szBuf[32];switch (uType)case XTYP_ADVREQ:case XTYP_REQUEST:if
((hsz1 == hszTime &hsz2 == hszNow) &
(uFmt== CF_TEXT))// Копируем строку
в буфер.itoa(tmTime.hour, szBuf, 10);lstrcat(szBuf, ":");if (tmTime.minute