РефератыИнформатика, программированиеПрПротоколы и стандарты объектно-ориентированного программирования

Протоколы и стандарты объектно-ориентированного программирования

Clipboard

РЕФЕРАТ


по
дисциплине
"Теория проектирования
трансляторов"


на
тему Протоколы
и стандарты
объектно-ориентированного
программирования

Выполнен
студентом
группы АП-1-91
Маслюковым
А.О.

СОДЕРЖАНИЕ

Предисловие


MS
Windows и новый метод
разработки
программ


Динамический
обмен данными


OLE-технология


Заключение


Список
литературы


Приложение
1.Пример использования
OLE-технологии


Предисловие

Наиболее
распространенным
языком программирования
последне-


го
десятилетия
безусловно
является С.
Этому способствовали
такие


его
особенности,
как лаконичность,
мощность, гибкость,
мо-


бильность.
Вместе с тем,
стремительное
усложнение
приложений,
для


реализации
которых применяются
традиционные
процедурно-ориентиро-


ваннные
языки программирования
и, в частности
С, заставляют
гово-


рить
об определенном
кризисе в их
использовании,
связанном
преж-


де
всего с недостаточной
надежностью
и выразительной
способностью.


Подобных
недостатков
во многом лишены
языки объектно-ориен-


тированнго
программирования
(ООП), в сонове
которыхлежит
идея мо-


делирования
объектов посредством
иерархически
связанных
классов.


Отдельно
взятый класс
рассматривается
как совакупность
множества


данных
и операций над
ними, причем
доступ к элементам
данных


класса
возможен только
посредством
операций этого
класса. Уста-


новление
четкой взаимозависимости
между данными
и операциями
ве-


дет
к большой целостности
данных и значительно
повышает надеж-


ность
программ по
сравнению с
традиционными
языками программиро-


вания.
Кроме того,
идея программирования
с помощью классов
во


многом
использует
тот же подход,
который позволяет
людям формиро-


вать
модели объектов
реального мира.


Впервые
идеи ООП были
реализованы
в середине
60-х годов в


языке
программирования
Симула-67. Последний,
однако, не нашел
в


то
время широкого
распространения
как в силу своей
относительно


меньшей
производительности
по сравнению
с традиционными
языками


типа
FORTRAN, ALGOL, PL/1 так и, возможно,
неадекватности
предла-


гаемых
средств решаемым
в то время задачи.
Еще одним важным
огра-


ничением
для распространеия
Симулы-67 стали
трудности, с
которы-


ми
пришлось столкнуться
большинству
программистов
при его изуче-


нии.
Дело в том, что
наряду с целым
рядом безусловных
достоинств,


идеи
ООП обладают
и одним существенным
недостатком
- они далеко


не
просты для
понимания и
особенно для
освоения с
целью практи-


ческого
использования.

С++
- развитие С.


С++
- это объектно-ориентированыый
язык, то есть
язык, поз-


воляющий
программисту
оперировать
объектами
некоторых
типов,


предварительно
им определенным.
Название языка
"С++" отражает


эволюционный
характер изменения
языка С (запись
"++", в языке С,


означает,
что к какой-то
переменной
прибавляется
единица). Он


имеет
еще более мощные
и гибкие средства
для написания
эффектив-


ных
программ, чем
С, от которого
он произошел.
Человек, програм-


мирующий
на традиционных
языках, может
просто потерять
голову от


тех
возможностей,
которые предоставляет
С++.


Но
не менее важным
является то,
что такой
распространенный
и


универсальный
язык, как С, сохранен
в качестве
основы. С прост,


эффективен,
переносим. Чего
только нет в
языке С: строковых
дан-


ныхнет,
матриц нет,
средств параллельного
программирования
тоже


нет.
Нет даже ввода-вывода.


Типы,
операции и
операторы С
очень близки
к тому, с чем
мы


имеем
дело в Ассемблере,-
числа, адреса,
арифметические
и логи-


ческие
действия, циклы...
Кроме того,
многие особенности
С нед-


вусмысленно
намекаю компилятору,
как сократить
код и время
испол-


нения
программы. Эти
характерные
черты языка
С позволяют
напи-


сать
эффективно
работающий
и не слишком
сложный компилятор.
И хо-


тя
в машинных
кодах на разных
компьютерах
элементарные
операции


обозначаютс
по-разному,
вряд ли разработчику
компилятора
придет в


голову
интерпретировать
простейшие
выражения
каким-нибудь
ориги-


нальным
способом. Именно
поэтому язык
С "идет везде
и на всем",


программы,
написанные
на нем, работают
эффективно,
и их можно пе-


реносить
с одного компьютера
на другой.


Большинство
языков программирования
созданы для
решения оп-


ределенного
круга задач.
В них не только
не хватает
определенных


типов
данных и функций,
но и много лишнего
с точки зрения
челове-


ка,
далекого от
области, на
которую ориентирован
язык. Специали-


зированные
типы данных
или операторы,
требующие
нетривиальной


поддержки,
затрудняют
изучение языка
и мешают вашей
работе, если


вы
ими не собираетесь
пользоваться.
Поэтому С, в
котором нет
ни-


чего
лишнего, популярен
среди широкого
круга программистов.
Соот-


ветствующие
библиотеки
могут добавить
к средствам
языка специали-


зированные
функции для
работы со строками,
файлами, списками,
ус-


тройствами
ввода-вывода,
математическими
объектами и
т.д. Остает-


ся
только выбрать
то, что нужно
лично вам.
Заголовочные
файлы об-


легчают
использование
библиотек,
предоставляют
полезные типы
дан-


ных,
глобальные
переменные,
макроопределения...
Они во многом
ус-


траняют
противоречие
между эффективностью
программы и
удобством


использования
библиотечных
функций. Они
также позволяют
не повто-


рятся
и не писать по
нескольку раз
одно и тоже в
различных
прог-


раммах.
Поскольку С
был создан
специально
для системного
програм-


мирования,
он имеет возможности
низкого уровня,
позволяющие
"иг-


рать
без правил".
В зависимости
от устройства
и операционной
сис-


темы
вашей машины
вы можете "влезть"
в видеопамять
или использо-


вать
системные
программы,
находящиеся
в оперативной
памяти.


В
любом случае
вы можете
рассматривать
код собственной
прог-


раммы
как данные, а
массив данных
как код функции,
квадратную


матрицу
как вектор, а
текст как бинарное
дерево. Что бы
ни нахо-


дилось
в памяти - это
всего лишь
последовательная
цепочка чисел.


Если
вы не боитесь
риска - можете
делать все, что
вам вздумается.


Современные
прграммисты
выбирают С не
только из-за
его преи-


муществ.
В настоящее
время мы имеем
дело с цепной
реакцией: чем


больше
написано на
С, тем больше
на нем напишут
еще. Это одна
из


причин,
почему язык
С++ сохраняет
С в качестве
подмножества.


По
мнению автора
С++, Бьерна Страуструпа,
различие между


идеологией
С и С++ заключается
примерно в
следующем:
программ на


С
отражает "способ
мышления"
процессора,
а С++ - способ
мышления


программиста.
Отвечая требованиям
современного
программирования,


С++
делает акцент
на разработке
новых типов
данных, наиболее
пол-


но
соответствующих
концепциям
выбранной
области знаний
и задачам


приложения.
На С пишут библиотеки
функций, С++
позволяет
созда-


вать
библиотеки
классов. Класс
является ключевым
понятием С++.


Описание
класса содержит
описание данных,
требующихся
для пред-


ставления
объектов этого
типа, и набор
операций для
работы с по-


добными
объектами.


В
отличие от
традиционных
структур С или
Паскаля, членами


класса
являются не
только данные,
но и функции.
Функции-члены


класса
имеют привилегированный
доступ к данным
внутри объектов


этого
класса и обеспечивают
интерфейс между
этими объектами
и ос-


тальной
программой.
При дальнейшей
работе совершенно
не обяза-


тельно
помнить о внутренней
структуре
класса и мехагизме
работы


"встроенных
функций". В этом
смысле класс
подобен электрическому


прибору
- мало кто знает
о его устройстве,
но все знают,
как им


пользоваться.


Часто
в целях повышения
эффективности
и упрощения
структуры


программы
приходится
заставлять
ее работать
с разнородными
объек-


тами
так, как если
бы они имели
один и тотже
тип. Например,
ок-


ружность
и квадрат естественно
рассматривать
как варианты
геомет-


рической
фигуры. Полезно
составлять
списки фигур,
нарисованных
на


экране,
или функций,
которые их
размножают,
двигают и т.д.
О точ-


ном
типе объекта
приходится
порой забывать.
Список геометричес-


ких
фигур "не знает",
что в нем находится
- отрезки или
звездоч-


ки.
Не знает этого
и компилятор.
Но все время,
пока вы рисуете


эти
объекты, неизбежно
приходится
"помнить", что
они из себя


представляют.
Конечно, возможности
низкого уровня
позволяют "за-


бывать"
и "вспоминать"
когда и как нам
заблагорассудится,
но при


этом
компилятор
теряет контроль
над осмысленностью
действий.


Использование
производных
классов и виртуальных
функций поз-


воляет
избежать рискованной
техники и не
заботится о
том, в ка-


кой
форме объект
типа "геометрическая
фигура" хранит
информацию
о


том,
круг он или
квадрат. (Кроме
возможностей
ООП, создание
ти-


пов
данных "треугольник"
или "квадрат"
как производные
от базово-


го
класса "геометрическая
фигура" отражает
логическую
связь поня-


тий).
Виртуальные
функции, по
существу,
определяют,
что именно


можно
делать с объектом,
а не то, как это
делать. Создавая
класс


"геометрическая
фигура", мы
можем включить
в него виртуальные


функции
рисования,
увеличения,
поворота. С
использованием
этих


функций
можно создать
еще один член
класса.


Затем
можно разработать
библиотеку
программ
интерактивной


графики,
снабдив ее
средствами
диалого, функциями
вроде дополне-


ния
некоторой
области экрана
одинаковыми
геометрическими
фигура-


ми
и т.д. Библиотечные
функции будут
вызывать
функции-члены
клас-


са
"геометрическая
фигура": рисования,
движения,
поворота,увели-


чения.
А после того,
как мы все это
напишем, откомпилируем,
спря-


чем
текст функций,
которые считаем
своей интеллектуальной
соб-


ственностью,
начинается
самое интересное.
Теперь мы можем
опи-


сать
сколько угодно
новых типов
фигур - многоугольников,
звездо-


чек,
эллипсов -
производных
от класса
"геометрическая
фигура" и


объяснить,
как их рисовать,
увеличивать
и поворачивать.
Как дви-


гать
- объяснять не
надо. Это уже
есть в базовом
классе. Функции


нашей
библиотеки
могут работать
собъектами
вновь созданных
типов,


для
них это варианты
геометричесой
фигуры. Следует
отметить, что


в
производных
классах могут
(и, как правило,
должны) появлятся


данные
и функции, которых
нет в базовом
классе. Однако
ни одна из


функций,
обрабатывающих
"геометрические
фигуры", никогда
не уз-


нает
о специфических
свойствах
многоугольника
или эллипса,
кроме


того,
что они по-своему
рисуются,
увеличиваются
и поворачиваются.


Производный
класс сам может
быть базовым
для других
классов, а


поздние
версии С++ позволяют
сделать один
класс производным
от


нескольких
других.


При
написании
программы часто
допускаются
досадные оплошнос-


ти,
обнаруживающиеся
только на стадии
выполнения
и, увы, слишком


поздно.
Например, если
переменная
по смыслу -
знаменатель
дроби,


хотелось
бы получить
сообщение об
ошиюке тогда,
когда ей присваи-


вается
ноль, а не тогда,
когда на этот
ноль что-нибудь
делится.


Или,
скажем, функция
рисования
точки. Невозможно
удержаться
от


соблазна
вызвать ее хотя
бы раз без проверки
выхода за границы


экрана.
В то же время
, если мы пишем
программу
рисования
линии,


обязательно
нужна функция,
которая тупо
ставит точку
- и как мож-


но
быстрее. Существует
много ситуаций,
когда функции
и данные


следует
разрешить
использовать
только привилегированным
функциям,


над
которыми ва
"хорошо подумали".
В С++ этого можно
добиться,


сделав
"опасные" данные
и функции защищенными
членами какого-ни-


будь
класса. К ним
имеют доступ
только функции-члены
этого же


класса,
а так же друзья
класса. Напротив,
если данные
или фун-


кции-члены
объявлены
public, они являются
общедоступными.


С++
предоставляет
в распоряжение
программиста
сложные типы


данных.
Однако ни аппарат
классов, ни
перегрузка
операций не


влияют
на эффективность.
То, что класс
- это класс,
известно


только
компилятору.
Если функции-члены
классов объявлены
inline,


на
их вызов не
требуется
время. Фактически
это не функции,
а под-


становки.
Лишь виртуальные
функции оставляют
относительно
не-


большой
след в оперативной
памяти.


Из
всего выше
сказанного
вытекает логичный
вывод: С++ наибо-


лее
удобный, универсальный
и необходимый
язык. Но все
же возни-


кает
вопрос, что же
было написано
на этом языке,
используя
прин-


ципы
ООП, что можно
было бы "потрогать"
любому программисту
или


пользователю.
Ответ очевиден
- это Microsoft Windows.



MS Windows и
новый метод
разработки
программ.

Одним
из наиболее
важных механизмов
взаимодействия
программ


является
обмен данными.
В MS Windows существует
несколько
способов


взаимодействия
приложений:


-
почтовый ящик;


-
динамический
обмен данными;


-
встраивание
объектов.

Специальный
почтовый ящик
(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-диалог
- взаимосвязь
между клиентским
и серверным
при-


ложениями.


Сервер-приложение
- DDE приложение,
которое передает
дан-


ные
клиенту в процессе
диалога.


DDE-Транзакция
-обмен сообщениями
или данными
между клиен-


том
и сервером.


Item
имя - строка,
идентифицирующая
некоторое
множество


данных,
которое сервер
в состоянии
передать клиенту
в процессе


диалога.


Service
имя - строка,
генерируемая
сервером и
используе-


мая
клиентом для
установления
диалога.


Строковый
указатель -
двойное слово,
генерируемое
опера-


ционной
системой,
идентифицирующее
строку, передающуюся
в процес-


се
динамического
обмена данными.


Topic
имя - строка,
которая идентифицирует
тип данных,


необходимых
клиентскому
приложению
при динамическом
обмене данных.


Фильтр
транзакции
- флаг, который
препятствует
передаче


нежелательных
типов транзакций
в функцию обратного
вызова.

В
Microsoft Windows динамический
обмен данных
является фор-


мой
связи, которая
использует
общие области
памяти для
обмена


данными
между приложениями.
Приложение
может использовать
DDE в


некоторый
момент времени
для передачи
и получения
новых данных
от


сервера.


Механизм
DDE схож с механизмом
почтового
ящика, который
яв-


ляется
частью операционной
системы WINDOWS. Существует
лишь нез-


начительная
разница в том,
что почтовый
ящик, в большинстве
слу-


чае,
используется
как буфер временного
хранения информации.
DDE


может
быть инициализирован
пользователем
и в большинстве
случаев


продолжать
работать без
его вмешательства.


Библиотека
DDEML обеспечивает
пользователя
набором средств,


которые
упрощают
использование
механизма DDE в
WINDOWS приложе-


ниях.
Вместо того,
чтобы обрабатывать,
получать и
передавать
DDE


сообщения
напрямую, приложения
используют
функции DDEML библиоте-


ки.
Библиотека
DDEML также обеспечивает
работу со строками
и раз-


деляемыми
данными, генерируемыми
DDE приложениями.
Вместо того,


чтобы
использовать
указатели на
общие области
памяти, DDE прило-


жения
создают и
обмениваются
строковыми
указателями,
которые


идентифицируют
строки и данные.


Уже
существующие
приложения,
использующие
протокол DDE, ос-


нованный
на сообщениях
полностью
совместимы
с теми, которые
ис-


пользуют
библиотеку
DDEML. Вот почему
приложение,
использующее


DDE-протокол
могут установить
диалог и выполнять
транзакции
с


приложениями,
использующими
библиотеку
DDEML.


Взаимосвязь
между клиентом
и сервером.


DDE
возникает
всегда между
клиентским
приложением
и сервер-


ным.
Клиентское
приложение
инициализирует
обмен данными
путем ус-


тановления
диалога с сервером
и передачи
транзакции.
Транзакция


необходима
для данных и
обслуживания.
Сервер отвечает
на транзак-


цию
и обеспечивает
клиента данными.
Сервер может
иметь сразу
нес-


колько
клиентов в одно
и тоже время,
в свою очередь,
клиент мо-


жет
получать данные
сразу от нескольких
серверов. Некоторое
при-


ложение
одновременно
может быть и
клиентом и
сервером. В
добавок


к
вышесказанному,
клиент и сервер
могут оборвать
диалог в любое


удобное
для них время.


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 и


содержит
строку типа
Готов/Занят.


SZDDE
ITEM ITEMLIST - список item имен,
поддерживаемых
сер-


вером
в несистемном
режиме работы.
Этот список
может меняться


время
от времени.


SZDDESYS
ITEM FORMATS - список строк,
представляющий
собой


список
всех форматов
почтового
ящика, поддерживаемых
сервером в


данном
диалоге. Например,
CF_TEXT формат представлен
строкой TEXT.

Основное
назначение
и работа функции
обратного
вызова


Приложение,
которое использует
DDEML, должно содержать
фун-


кцию
обратного
вызова, которая
обрабатывает
события, полученные


приложением.
DDEML уведомляет
приложение
о таких событиях
путем


посылки
транзакций
в функцию обратного
вызова данного
приложения.


В
зависимости
от флага фильтра
транзакции,
сформированного


при
вызове функции
DdeInitialize, функция
обратного
вызова полу-


чает
отсортированные
транзакции
вне зависимости
от того, являет-


ся
ли данное приложение
клиентом, сервером
или тем и другим
од-


новременно.
Следующий
пример демонстрирует
наиболее типичное
ис-


пользование
функции обратного
вызова.


HDDEDATA
CALLBACK DdeCallback( uType, uFmt, hconv, hsz1,


hsz2,
hdata, dwData1, dwData2 )


UINT
uType; // Тип транзакции


UINT
uFmt; // Формат почтого
ящика


HCONV
hconv; // Идентификатор
диалога


HSZ
hsz1; // Идентификатор
строки #1


HSZ
hsz2; // Идентификатор
строки #2


HDDEDATA
hdata; // Идентификатор
глобального
объек-



та
памяти


DWORD
dwData1; // Данные текущей
транзакции
#1


DWORD
dwData2; // Данные текущей
транзакции
#2


{


switch
(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 для посылки
транзакций
и для их обработки.
Клиенту мо-


жет
потребоваться
диалог как с
одним сервером,
так и с нескольки-


ми.


Рассмотрим
подробно как
приложение
устанавливает
диалог и


получает
информацию
о уже существующих
каналах связи.


Простой
Диалог


Клиентское
приложение
устанавливает
простой диалог
с серве-


ром
путем вызова
функции 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 5

HSZ
hsz1; // Идентификатор
строки,



полученный
от DDEML.

HSZ
ahszTopics[CTOPICS]; // Массив
поддреживаемых



topic
имен


int
i; // Счетчик
цикла


.


.
// Для обработки
транзакций
используем
стандартную



ANSI C


.
// конструкцию
switch --> case --> default.


.

case
XTYP_CONNECT:


for
(i = 0; i < CTOPICS; i++)


{



if (hsz1 ==
ahszTopics[i])



return TRUE;
// Установка
диалога


}


return FALSE; //
Topic имя НЕ поддерживается,



диалог
запрещен.


.


.
// Обработка
других типов
транзакций.


.

Если
сервер возвращает
TRUE в ответ на
транзакцию


XTYP_CONNECT,
DDEML посылает
транзакцию
вида XTYP_CONNECT_CONFIRM


в
функцию обратного
вызова данного
сервера. Обработав
эту тран-


закцию,
сервер может
получить
идендификатор
диалога.


Вместо
конкретного
имени сервера
клиент может
установить


шаблон
диалога путем
установки
идентификаторов
service и topic


имен
в NULL при вызове
функции DdeConnect.


Если
хотя бы один
из вышеперечисленных
идентификаторов
ра-


вен
NULL, DDEML посылает
транзакцию
типа XTYP_WILDCONNECT в фун-


кцию
обратного
вызова всех
активных в
данный момент
DDE-приложе-


ний
(исключения
составляют
лишь те, кто
при вызове
соответствую-


щей
функции указал
флаг фильтрации
XTYP_WILDCONNECT).


Любое
сервер-приложение
должно ответить
на данную транзак-


цию
и возвратить
указатель на
массив структур
типа HSZPAIR, окан-


чивающийся
нулем.


Если
сервер-приложение
НЕ вызывает
функцию DDeNameService


для
регистрации
собственного
service имени в системе
и фильтр об-


работки
транзакций
включен, то
сервер НЕ получит
транзакцию
вида


XTYP_WILDCONNECT.


Вышеописанный
массив должен
содержать
одну структуру
для


каждого
service и topic имен. DDEML выбирает
одну пару из
масси-


ва
для установления
диалога и возвращает
его идентификатор
клиен-


ту.
Затем DDEML посылает
серверу транзакцию
вида


XTYP_CONNECT_CONFIRM
(исключения
составляют
лишь те серверы,
ко-


торые
при инициализации
установили
фильтр обработки
транзакций).


Продемонстируем
использование
транзакции
вида XTYP_CONNECT.


#define CTOPICS
2

UINT
uType;



HSZPAIR
ahszp[(CTOPICS + 1)];


HSZ
ahszTopicList[CTOPICS];


HSZ
hszServ, hszTopic;


WORD
i, j;

if
(uType == XTYP_WILDCONNECT)


{


//
Сканируем
список topic имен
и создаем мас-



сив
структур типа
HSZPAIR

j
= 0;


for
(i = 0; i < CTOPICS; i++)


{



if (hszTopic ==
(HSZ) NULL ||



hszTopic
== ahszTopicList[i])



{



ahszp[j].hszSvc
= hszServ;



ahszp[j++].hszTopic
= ahszTopicList[i];



}


}

//


//
Последний
элемент массива
всегда NULL.


//


ahszp[j].hszSvc
= NULL;



ahszp[j++].hszTopic
= NULL;

//


//
Возвращаем
дискриптор
глобального
объекта


//
памяти,содержащий
структуры типа
HSZPAIR.


//


return
DdeCreateDataHandle(



idInst,
// Копия приложения



(LPBYTE) &ahszp,
// Указатель на
массив



типа
HSZPAIR


sizeof(HSZ) * j,
// Длина массива



0,
// Начальное
смещение



(HSZ) NULL,
// item-имя не существует



0,
// формат item-имени
также



//
не существует



0);
// Возлагаем
все работу



//
с массивом на
систему


}

Любой
сервер или
клиент может
оборвать диалог
в любое вре-


мя
путем вызова
функции DdeDisconnect. Это
означает, что
партнер


по
обмену данными
получает транзакцию
типа XTYP_DISCONNECT в фун-


кц

ии
обратного
вызова (если,
конечно, партнер
не установил
фильтр


обработки
транзакций
вида CBF_SKIP_DISCONNECTIONS).


Обычно
приложение
реагирует на
транзакцию
XTYP_DISCONNECT


вызовом
функции DdeQueryInfo для
получения
информации
о прекра-


щенном
диалоге. После
того, как функция
обратного
вызова обрабо-


тала
транзакцию
типа XTYP_DISCONNECT, идентификатор
диалога


больше
не существует.


Клиентское
приложение,
которое получает
транзакцию
типа


XTYP_DISCONNECT
в своей функции
обратного
вызова может
попы-


таться
возобновить
диалог при
промощи вызова
функции


DdeReconnect.
Клиентское
приложение
может вызывать
эту функцию


только
находясь внутри
своей собственной
функции обратного
вызова.


Сложный
диалог


Клиентское
приложение
может использовать
функцию


DdeConnectList
для того, чтобы
определить
какие сервер-приложе-


ния
существуют
в системе в
данный момент
времени.


Клиент
обязательно
должен описывать
service и topic имена,


когда
он вызывает
эту функцию;
это означает,
что DDEML должна


послать
транзакцию
вида XTYP_CONNECT все
функции обратного
вызо-


ва
всех имеющихся
в данный момент
сервер-приложений,
чьи зарегис-


трированные
имена совпадают
с именами, указанными
клиентом (ис-


ключение
составляют
лишь те серверы,
которые фильтруют
получае-


мые
транзакции).


В
добавление
к вышесказанному,
можно отметить,
что клиент,


при
вызове функции
DdeConnectList, может указать
NULL в качестве


service
или topic имени, либо
же сразу для
обоих. Все доступные
в


системе
серверы, чьи
зарегистрированные
имена совпадают
с имена-


ми,
указанными
клиентом, отвечают
на его запрос.
Диалог устанав-


ливается
со всеми такими
серверами, даже
если в системе
запущено


одно
и тоже сервер-приложение
несколько раз.


Клиент
может использовать
функции
DdeQueryNextServer и


DdeQueryConvInfo
для того, чтобы
понять, какой
сервер находится
в


списке,
полученный
при вызове
функции
DdeConnectList.


DdeQueryNextServer
возвращает
идентификатор
диалога для
следующе-


го
сервера, находящегося
в списке;
DdeQueryConvInfo заполняет


структуру
CONVINFO информацией
о диалоге.


Клиент
может сохранить
полученные
идентификаторы
диалогов и


отказаться
от просмотра
оставшихся
серверов в
списке.


Приведем
пример использования
функции DdeConnectList
для


установления
диалога со
всеми серверами,
которые поддерживают
имя


'system
topic', затем будем
использовать
функции DdeQueryConvInfo


и
DdeQueryNextServer для получения
их идентификаторов
service


имен,
одновременно
не забывая
сохранить
последние во
временном


буфере.


HCONVLIST
hconvList; // Список диалогов


DWORD
idInst; // Дискриптор
приложения


HSZ
hszSystem; // System topic


HCONV
hconv = NULL; // Идентификатор
диалога


CONVINFO
ci; // Информация
о диалоге


UINT
cConv = 0; // Количество
идентификаторов



диалогов


HSZ
*pHsz, *aHsz; // Указатель
на идентификатор



строки

//
Присоединяемся
ко всем серверам,
поддерживающим


//
System topic.



hconvList =
DdeConnectList(idInst, NULL, hszSystem,



NULL,
NULL);

//
Вычисляем
количество
серверов в
списке.


while((hconv =
DdeQueryNextServer(hconvList,hconv))



!= NULL)



cConv++;

//
Выделяем буфер
для сохранения
идентификаторов
строк.

hconv
= NULL;


aHsz
= (HSZ *) LocalAlloc(LMEM_FIXED, cConv * sizeof(HSZ));

//
Копируем
идентификатор
строки в буфер.

pHsz
= aHsz;


ile((hconv
= DdeQueryNextServer(hconvList,hconv)) != NULL)


{



DdeQueryConvInfo(hconv,
QID_SYNC, (PCONVINFO) &ci);


DdeKeepStringHandle(idInst,
ci.hszSvcPartner);



*pHsz++ =
ci.hszSvcPartner;


}


.


.
// Используем
идентификатор:
'общаемся' с
сервером.


.

//
Освобождаем
память и прекращаем
диалог.


LocalFree((HANDLE)
aHsz);



DdeDisconnectList(hconvList);

Приложение
может оборвать
индивидуальный
диалог, находящий-


ся
в списке диалогов
путем вызова
функции DdeDisconnect;
приложе-


ние
может оборвать
все диалоги,
находящиеся
в списке путем
вызо-


ва
функции DdeDisconnectList.


Обе
вышеуказанные
функции указывают
DDEML о необходимости


посылки
транзакции
вида XTYP_DISCONNECT во все
функции партнеров


по
диалогу данного
приложения
(в случае использования
функции


DdeDisconnectList
будет посылаться
транзакция
XTYP_DISCONNECT для


каждого
элемента в
списке диалогов).

Обмен
данными между
приложениями


Так
как DDE использует
области памяти
для передачи
данных


из
одного приложения
в другое, DDEML
обеспечивает
конечного прог-


раммиста
функциями, при
помощи которых
DDE-приложения
могут соз-


давать
и обрабатывать
DDE-объекты.


Весь
спектр транзакций,
который вызывает
обмен данными,


требует
от приложения,
экспортирующего
их, создания
некоторого


буфера,
содержащего
эти данные,
а затем вызова
функции


DdeCreateDataHandle.


Эта
функция создает
DDE-объект, копирует
данные из буфера
в


этот
объект и возвращает
идентификатор
данных для
данного прило-


жения.


Идентификатор
данных-это
двойное слово,
которое использует


DDEML
для обеспечения
доступа к данным
в DDE-объекте.


Для
того, чтобы
разделять
данные в DDE-объекте,
приложение


передает
идентификатор
данных DDEML, а затем
DDEML передает его
в


функцию
обратного
вызова приложения,
получающего
данные.


В
нижеприведенном
примере показано,
как создать
DDE-объект


и
получить его
идентификатор.
В процессе
обработки
транзакции
ти-


па
XTYP_ADVREQ, функция
обратного
вызова конвертирует
текущее


время
в ASCII строку, копирует
строку в вспомогательный
буфер, а


затем
создает DDE-объект,
содержащий
вышеуказанную
строку. Фун-


кция
обратного
вызова возвращает
идентификатор
DDE-объекта DDEML,


которая
передает этот
идентификатор
клиентскому
приложению.

typedef
struct tagTIME


{


INT
hour; // 0 - 11 формат
времени для



часов.


INT
hour12; // 12-ой формат.


INT
hour24; // 24-ой формат.


INT
minute;


INT
second;


INT
ampm; // 0 --> 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 < 10)



lstrcat(szBuf,
"0");



itoa(tmTime.minute,



&szBuf[lstrlen(szBuf)],
10);



lstrcat(szBuf,
":");



if
(tmTime.second < 10)



strcat(szBuf,
"0");



itoa(tmTime.second,



&szBuf[lstrlen(szBuf)],
10);



szBuf[lstrlen(szBuf)]
= '0';


// Создаем
глобальный
объект и



// возвращаем
его идентификатор


return
(DdeCreateDataHandle(



idInst,
// копия



приложения



(LPBYTE)
szBuf, // исходный



буфер



lstrlen(szBuf)
+ 1,



0,
// смещение



от
его начала



hszNow,
// item-имя



CF_TEXT,
// формат



почтого
ящика



0));



}


else return
(HDDEDATA) NULL;


.


.
// Обработка
других типов
транзакций.


.

}


}

Клиентское
приложение
получает указатель
на DDE-объект пу-


тем
передачи
идентификатора
данных функции
DdeAccessData. Указа-


тель,
возвращаемый
этой функцией,
обеспечивает
доступ к данным
в


формате
'ТОЛЬКО НА ЧТЕНИЕ'.
Клиент должен
просмотреть
полученные


данные
при помощи
этого указателя
и вызвать
функцию


DdeUnaccessData
для его уничтожения.
Клиент может
скопировать
по-


лученные
данные в заранее
приготовленный
буфер посредством
вызо-


ва
функции DdeGetData.


В
следующем
примере мы
получим указатель
на DDE-объект,


сохраним
его в параметре
hData, скопируем
содержимое
во времен-


ный
буфер и уничтожим
указатель:

HDDEDATA
hdata;


LPBYTE
lpszAdviseData;


DWORD
cbDataLen;


DWORD
i;


char
szData[32];

.
. .

case
XTYP_ADVDATA:



lpszAdviseData =
DdeAccessData(hdata,



&cbDataLen);


for
(i = 0; i < cbDataLen; i++)



szData[i] =
*lpszAdviseData++;



DdeUnaccessData(hdata);



return
(HDDEDATA) TRUE;


.
. .

Обычно,
когда приложение,
создающее
идентификатор
данных,


передает
его DDEML, этот
идентификатор
портится внутри
вышеука-


занного
приложения.
В этом нет ничего
страшного, если
сервер дол-


жен
разделять
данные только
с одним клиентом.
Если же сервер
дол-


жен
разделять
данные сразу
с несколькими
клиентами
одновременно,


ему
придется указывать
флаг HDATA_APPOWNED при
вызове функции


DdeCreateDataHandle.


Это
делает возможным
получение
прав собственности
на


DDE-объект
сервер-приложения
и предотвращает
порчу идентификато-


ра
данных DDEML. Приложение
может передавать
DDEML идентификатор


данных
любое количество
раз, однако
вызывать
функцию


DdeCreateDataHandle
можно лишь
однажды.


Если
приложение
указывает флаг
HDATA_APPOWNED в параметре


atCmd
при вызове
функции
DdeCreateDataHandle, оно обязательно


должно
вызывать функцию
DdeFreeDataHandle для очистки
памяти вне


зависимости
от того, передавался
ли идентификатор
данных DDEML


или
нет. Перед тем
как оборвать
диалог, приложение
должно вызы-


вать
функцию DdeFreeDataHandle
для очистки
всех созданных
иденти-


фикаторов,
но которые так
и не были переданы
DDEML.


Если
приложение
еще не передало
идентификатор
DDE-объекта


DDEML,
то оно может
добавить данные
к уже существующему
объекту


или
полностью
заменить их
в нем. Все эти
сервисные
функции обслу-


живаются
функцией DdeAddData.


Обычно
приложение
использует
эту функцию
для новой инициа-


лизации
старых не
уничтоженных
DDE-объектов. После
того, как при-


ложение
передает
идентификатор
данных DDEML, DDE-объект,
иденти-


фицирующий
этот идентификатор
НЕ может быть
изменен, однако
он


может
быть уничтожен.



OLE-технология

Как
видно из описанного
выше протокола
DDE, приложения


должны
обязательно
знать типы
передаваемых
данных, уметь
их обра-


батывать,
а в основном
даже могут
работать только
с символьными


строками.
Это, конечно,
не очень удобно,
когда необходимо,
напри-


мер,
создать небольшой
текст с различными
картинками,
пиктограм-


мами
и другими наглядными
или не очень
иллюстрациями.
В этом слу-


чае
на помощь
программисту
проиходит OLE -
встраивание
объектов.


Вместе
с данными мы
получаем машинный
код, который
эти данные мо-


жет
обрабатывать.

Способы
упорядочивания,
источники и
целевые документы


При
использовании
OLE-технологии
пользователь
всегда имеет


дело
с одним ведущим
приложением
(главным) и одним
ведомым (под-


чиненным),
а точнее, содним
ведомым.


Приложение,
с помощью которого
получен объект
для встраива-


ния
всегда играет
роль подчиненного.
Это особенно
характерно
для


случаев
передачи объектов
при встраивании
и связывании
через бу-


фер
промежуточного
обмена.


Часто
используемые
термины
Приложение-источник
и Целевое


приложение
касаются не
подчинения
приложений,
а определяют
генеа-


логию
объектов.


Некоторые
Windows-приложения
могут выступать
только в роли


подчиненных,
а некоторые
только в роли
ведущих. Например,


Paintbrush
в OLE технологии
может играть
только роль
подчиненно-


го
приложения,
служащего для
создания и
модификации
отдельных


объектов.
Другие приложения,
например, Write или
Cardfile можно


считать
оправданным
с точки зрения,
что гораздо
чаще приходится


вставлять
иллюстрации
в сложные по
структуре
текст, чем текст
в


иллюстрации.
Новые приложения,такие
как Word, могут
выполнять в


рамках
OLE обе эти функции.


Употребление
термина объект
считается
престижным
в кругах


программистов,
хотя часто он
употрябляется
и не к месту.
Всякий


разработчик
почитает своим
долгом применить
в своем продукте
ООП


без
особой на то
необходимости.
В среде Windows в термин
объект


вкладывается
несколько
специфический
смысл. Пользователя
не приг-


лашают
постигать азы
ООП, или заняться
конструированием
объектов


на
С++.


Когда
об объектах
говорят в рамках
Windows, то имеют в
виду


возможность
встраивания
в некоторый
документ фрагмента,
порожден-


ного
другим приложением.
Вот это "инородное
тело" и называется


объектом.


В
таком подходе
нет ничего
нового. Когда
в текст, подготав-


ливаемый
Write, вставляется
рисунок из
Paintbrush посредством


Clipboard
или таблиц
Exсel, в документ,
подготавливаемый
в Word,


то
результатом
действия будет
как раз появления
объекта.


Традиционные
объекты всегда
представляют
собой копии.
Рабо-


та
с ними основывается
на том, что все
Windows приложения
поддер-


живают
не только свой
собственный
формат , но и
некоторый
обоб-


щенный,
стандартный,
играющий роль
общеизвестного
международного


языка.
Если, например,
в текстовый
документ вставляется
таблица


из
табличного
процессора,
то буффер
промежуточного
обмена преоб-


разует
ее в формат к
стандартному,
и тем самым
обеспечивает


вставку.
Такая копия
в текстовом
редакторе по
виду не отличается


от
оригиналу, но
она недоступна
для внесения
изменений.
Невозмож-


но,
вставив таким
способом копию
из Paintbrush в Write документ,


изменить
цвет, толщину
линий или масштаб.


Новые
объекты, доступные
в рамках Windows 3.1 очень
похожи


на
традиционные,
но они не являются
копиями - это
оригиналы. Они


имеются
в единственном
экземпляре
и находятся
непостредственно
в


целевых
документах.
Там они существуют
одновременно
в двух форма-


тах
- в стандартном
и в формате
приложения-источника.


Благодаря
стандартному
формату объект
может идицироваться
и


сохранять
в рамках целевого
документа.
Имеется возможность
обра-


ботки
объекта также,
как и любого
файла оригинала.
Ситуация выг-


лядит
так, словно
внутри объекта
встроен другой.
Это обеспечи-


вает
доступ к средствам
обработки
нового объекта
(приложению-ис-


точнику)
посредством
простого двойного
щелчка на объекте.


Встроенные
объекты


Информация,
вставленныя
в документ
целевого приложения,


представляет
собой объект.
Такой объект
встраивается
в документ,


обрабатываемый
ведущим приложением.
Это значит, что
он рассматри-


вается
как составная
часть данного
документа,
может распечаты-


ваться
и сохраняться
вместе с ним.
Такие объекты
могут содержать


информацию
любого типа:
текст, таблицы,
графики и др.


Встроенные
объекты существуют
только в единственном
экзем-


пляре
и тлько там,
где они встроены
- в целевом
документе.
Обра-


батываются
они своими
"родительскими"
программами,
вызываемыми


весьма
эффективным
спосбом, в отличае
от традиционного.


Связывание
с родительским
приложением


Следующей
весьма удобной
особенностью
встроенных
объектов


является
то, что они остаются
связанными
с породившим
их приложе-


ниями.
Благодаря этому
пользователь
избавляется
от необходимости


помнить
имена и директории
файлов-источников.
Достаточно
двойно-


го
щелчка на объекте
- и родительская
программа
запускается.


Важным
достоинством
подобного
связывания
встроенных
объек-


тов
является мобильность
документов.
Можно легко
перенести
такой


документ
с одной машины
на другую (необходимо
только чтобы
на них


обеих
была установлена
оболочка и были
необходимые
приложения
или


динамические
библиотеки
от них). Для
обработки
встроенных
объек-


тов
достаточно
будет щелкнуть
по ней дважды
и на другой
машине


произойдет
тоже самое, что
и на вашей:
вызовется
соответсвующее


приложение.
В этом случае
необходимым
условием переноса
является


наличие
на другой машине
текстового
редактора Write
и графическо-


го
редактора
Paintbrush.


При
работе в рамках
DDE такой перенос
не возможен,
точнее он


будет
включать в себя
не только перенос
самого файла-документа,


но
и связанных
с данным файлом
файлов-источников
и целевых фай-


лов
- всей структуры.


Перспективы
развития OLE


Технология
OLE делает только
первые шаги.
Пока только
неко-


торые
Windows приложения
являются OLE
совместимыми.
Среди утилит


группы
Accessories версии 3.1 такими
на сегоднешний
день являют-


ся
только Write, Paintbrush и
Cardfile. Но даже они
"в своем кру-


гу"
не допускают
вставки в
произвольном
направлении
(т.е. из лю-


бой
в любую другую).
В настаящее
время речь идет
о поддержке
наи-


более
оправданного
с практической
точки зрения
"напрвления


встраивания"
- из Paintbrush в Write и Сardfile
документа.


Чтобы
определить
какие из приложений
поддерживаю
OLE интер-


фейс,
необходимо
из OLE-совместимого
приложения
выполнить
дирек-


тиву
"ВСТАВИТЬ
ОБЪЕКТ" в меню
"Edit". В отрывшемся
окне будет


продемонстрирован
список доступных
встраиваемых
объектов.


В
настоящий
момент многие
компиляторы
уже ввели
поодержку


OLE
в свои библиотеки:
Borland C++ ver4.5. Пример
использования
OLE


технологии
приведен в
приложении
1. Данная программа
использует
соз-


данный
рисунок Paintbrush в
виде файла или
копирует его
из Clipboard.

Заключение

В
заключении
хотелось бы
отметить, что
существующие
способы


обмена
информации
возникали
вместе с развитием
Windows. Как сама


суть
Windows, они являются
продолжением
заложенной
в нее цель:


cпособность
работать с
файлами любых
форматов, на
любом оборудовании.


В
отличие от
стандартного
решения, когда
фирма-производитель
обо-


лочки
(типа Windows) пыталась
сама написать
различные
драйверы


для
поддержки
устройств и
различные
библиотеки
для поддержки


форматов
многочисленных
файлов других
пакетов, фирма
Microsoft


возложила
эту обязанность
на производителей
оборудования
и


программного
обеспечения.
Таким образом,
последовательное
разви-


тие
Clipboard-->DDE-->OLE является
продолжением
воплощения


идеи
"сам изобрел
- сам внедряй".
Естесственно,
наибольшие
на-


дежды
сейчас возлагаются
на OLE (ее новый
стандарт OLE.2), так
как


этот
стандарт позволяет
включать в себя
очень мощные
средства, такие


как
Multimedia. В одном файле
может находится
не только текст,


рисунок,
а и даже целый
фильм, полностью
озвученный
и готовый


к
показу.



СПИСОК
ЛИТЕРАТУРЫ

1.
Гладков С.А.
Фролов Г.В.
Программирование
в Microsoft Windows:


В
2-х частях.
М.:"ДИАЛОГ-МИФИ",
1992.

2.
Фойц С. Windows 3.1 для
пользователя.
Пер. с немецкого


Киев:BHV,
1992.

3.
Microsoft Windows Software Development Kit. Version 3.


Programmer's
Reference, Programming Tools, Windows Extensions.

4.
Charles Petzold. Programming Windows. Microsoft Press.

5.
Библия Windows 3.X. М.:
И.В.К. - Софт, 1992.

6.
Borland C++. Usres manual.

Приложение
1. Пример использования
OLE технологии

//
ObjectWindows - (C) Copyright 1992 by Borland International


//


//
oleclnt.cpp

//
Пример Ole Client программы,
испльзующей
OWL. Она показывает


//
пример использования
Ole functions, и C++ классов
.

//
Основное окно
позволяет
пользователю
создать paint brush


//
object, или копировать
его из clipboard.

#include


#include


#include


#include


#include


#include


#include


#include


#pragma
hdrstop

#include
"oleclnte.h"


#include
"oleclntr.h"


#include
"oleclnt.h"

//
статические
данные класса


LPOLECLIENTVTBL
TOwlClient::lpClientVtbl = NULL;


int
TOleDocWindow::nNextObjectNum = 0;

void
TOleApp::InitInstance()


{



TApplication::InitInstance();

vcfLink
= RegisterClipboardFormat( "ObjectLink" );


vcfNative
= RegisterClipboardFormat( "Native" );


vcfOwnerLink
= RegisterClipboardFormat( "OwnerLink" );


//
comments in owlole.h mention these ole clipboard formats


}

//
описание функций
OWL Object, которые


//
позволяют
хранить описание
Ole Object

int
FAR PASCAL _export StdCallBack(LPOLECLIENT lpClient,



OLE_NOTIFICATION
notification,


LPOLEOBJECT
lpObject )


{


return
(( PTOwlClient )lpClient)->TOleDocWindowThis->



CallBack(
lpClient ,



notification,



lpObject );


}

TOwlClient::TOwlClient(
PTOleDocWindow owner , HINSTANCE hInst )


{



TOleDocWindowThis
= owner;


if
( !lpClientVtbl )


{



lpClientVtbl =
new OLECLIENTVTBL;


if
( hInst == 0 ) {



lpClientVtbl->CallBack
= StdCallBack;


}
else {



lpClientVtbl->CallBack
= (TCallBack)


MakeProcInstance(
(FARPROC)StdCallBack,



hInst
);


}


}


lpvtbl
= lpClientVtbl;


}

void
TOleDocWindow::WMURedraw( RTMessage )


{


bObjectLoaded
= TRUE;


InvalidateRect(
HWindow, NULL, TRUE );


UpdateWindow(
HWindow );


}

#pragma
argsused


int
TOleDocWindow::CallBack( LPOLECLIENT lpOleClient ,

OLE_NOTIFICATION
oleNot,


LPOLEOBJECT
lpOleObject )


{


switch
( oleNot ) {


case
OLE_CHANGED:


case
OLE_SAVED:



PostMessage(
HWindow , WM_U_REDRAW, 0, 0L );



break;


case
OLE_CLOSED:



break;


case
OLE_QUERY_PAINT:



break;


case
OLE_RELEASE:



break;


case
OLE_RENAMED:



break;



default:



break;


}


return
TRUE;


}

void
TOleDocWindow::CMAbout( RTMessage )


{

MessageBox(
HWindow , "OLE Client Programn


Written
using ObjectWindowsnCopyright (c) 1992 Borland",



GetApplication()->Name,
MB_OK );


}

//
создание новой
paint brush


void
TOleDocWindow::CMPBrush( RTMessage )


{


BackupObject();


bObjectLoaded
= FALSE;

lstrcpy(
lpszObjectName, GetNextObjectName() );

ret
= OleCreate( "StdFileEditing",



(LPOLECLIENT)pOwlClient,



"PBRUSH",



lhClientDoc,



GetApplication()->Name,



&lpObject,



olerender_draw,



0 );

//
Создание Ole Object -
асинхронная
операция.


//
Необходимо
ожидать его
создание, иначе


//
могут возникнуть
ошибки при
обработке


//
сообщений этого
объекта.

wait(
ret , lpObject );

//
OleSetHostNames устанавливает
имя в сервере
OLE.

ret
= OleSetHostNames( lpObject, GetApplication()->Name,


lpszObjectName
);


wait(
ret , lpObject );


}

void
TOleDocWindow::CMUndo( RTMessage msg)


{


if
( lpUndoObject )


if
( lpUndoObject != lpObject )


{



LPOLEOBJECT
lpObjectToDelete = lpObject;



lpObject =
lpUndoObject;



lpUndoObject =
NULL;



ret = OleDelete(
lpObjectToDelete );



wait( ret ,
lpObjectToDelete );



bObjectLoaded =
bUndoObjectLoaded;



WMURedraw( msg
);


}

}

void
TOleDocWindow::CMCut( RTMessage msg)


{


CMCopy(
msg );



CloseCurrentOle();


}

void
TOleDocWindow::CMCopy( RTMessage )


{


if
( OpenClipboard( HWindow ) && EmptyClipboard() )


{


ret
= OleCopyToClipboard( lpObject );


check(
ret );



CloseClipboard();


}


}

void
TOleDocWindow::BackupObject()


{


if
( lpObject )


{


ret
= OleClone( lpObject, (LPOLECLIENT)pOwlClient,



lhClientDoc,
GetApplication()->Name,



&lpUndoObject
);


wait(
ret, lpObject );



lstrcpy(
lpszLastObjectName, lpszObjectName );



lstrcpy(
lpszObjectName , GetNextObjectName() );



bUndoObjectLoaded
= bObjectLoaded;


}


}

void
TOleDocWindow::CMPaste( RTMessage )


{


if
( OpenClipboard( HWindow ) )


{



BackupObject();


lstrcpy(
lpszObjectName, GetNextObjectName() );

ret
= OleCreateFromClip( "StdFileEditing",



(LPOLECLIENT)pOwlClient,



lhClientDoc,



lpszObjectName,



&lpObject,



olerender_draw,



0 );


check(
ret );

ret
= OleSetHostNames( lpObject,



GetApplication()->Name,
lpszObjectName );


wait(
ret , lpObject );


bObjectLoaded =
TRUE;


CloseClipboard();



PostMessage(
HWindow , WM_U_REDRAW, 0, 0L );


}

}

LPSTR
TOleDocWindow::GetNextObjectName()


{


static
char buffer[ MAXPATH ];


wsprintf(
buffer, "object #%03d", nNextObjectNum++ );


return
buffer;


}

void
TOleDocWindow::Paint( HDC hdc, PAINTSTRUCT _FAR &)


{


LPOLEOBJECT
lpObjectToDraw = NULL;

if
( bObjectLoaded )



lpObjectToDraw =
lpObject;


else
if ( lpUndoObject )



lpObjectToDraw =
lpUndoObject;

if
( lpObjectToDraw ) {


RECT
rect;



GetClientRect(
HWindow, &rect );

//
Замечание по
OleDraw:


//
OleDraw должен возвращать
OLE_ERROR_OBJECT, если


//
object был нарисован
неверно.


ret
= OleDraw( lpObjectToDraw , hdc, &rect ,



NULL, 0
);


wait(
ret, lpObjectToDraw );


}


}

TOleDocWindow::TOleDocWindow(
PTWindowsObject parent,



LPSTR
title )


:
TWindow( parent, title )


{


ret
= OLE_OK;


lhClientDoc
= 0;

bObjectLoaded
= FALSE;



bUndoObjectLoaded
= FALSE;



bUndoObjectLoaded
= FALSE;

pOwlClient
= NULL;


lpObject
= NULL;


lpUndoObject
= NULL;

strcpy(
lpszDocName , "noname.ole" );



*lpszLastObjectName
= 0;


*lpszObjectName
= 0;


bDefDocName
= TRUE;


}

void
TOleDocWindow::SetupWindow() {



TWindow::SetupWindow();



RegisterClientDoc();


pOwlClient
= new TOwlClient( this );

}

void
TOleDocWindow::RegisterClientDoc() {

ret
= OleRegisterClientDoc(



GetApplication()->Name,



lpszDocName,



0,



&lhClientDoc
);


check(
ret );


}

void
TOleDocWindow::ShutDownWindow()


{



CloseCurrentOle();


if
( pOwlClient ) delete pOwlClient;



TWindow::ShutDownWindow();


}

void
TOleDocWindow::RegFileName( LPSTR FileName )


{


lstrcpy(
lpszDocName , FileName );


ret
= OleRegisterClientDoc( GetApplication()->Name,



lpszDocName ,



0,



&lhClientDoc
);


check
( ret );


}

void
TOleDocWindow::CMActivate( RTMessage )


{


BackupObject();


RECT
rect;


GetClientRect(
HWindow, &rect );


ret
= OleActivate( lpObject , OLEVERB_PRIMARY, TRUE,



TRUE ,



HWindow , &rect
);


wait
( ret, lpObject );


PostMessage(
HWindow , WM_U_REDRAW, 0, 0L );


}

void
TOleDocWindow::WMInitMenu( RTMessage msg )


{


HMENU
hMenu = (HMENU)msg.WParam;


WORD
wEnableUndo;

if
( (lpObject != lpUndoObject) &&


(
lpUndoObject != NULL ))



wEnableUndo =
MF_ENABLED;


else
wEnableUndo = MF_GRAYED;


EnableMenuItem(
hMenu, CM_UNDO ,



wEnableUndo );


EnableMenuItem(
hMenu, CM_COPY ,


(
bObjectLoaded ? MF_ENABLED : MF_GRAYED ));


EnableMenuItem(
hMenu, CM_CUT ,


(
bObjectLoaded ? MF_ENABLED : MF_GRAYED ));


ret
= OleQueryCreateFromClip( "StdFileEditing",



olerender_draw,
0 );


EnableMenuItem(
hMenu, CM_PASTE ,


((
ret == OLE_OK ) ? MF_ENABLED : MF_GRAYED ));


EnableMenuItem(
hMenu, CM_ACTIVATE ,


(
bObjectLoaded ? MF_ENABLED : MF_GRAYED ));


EnableMenuItem(
hMenu, CM_CLEAR ,


(
bObjectLoaded ? MF_ENABLED : MF_GRAYED ));

DrawMenuBar(
HWindow );


}

LPSTR
TOleDocWindow::GetClassName() { return "OLEDOCWINDOW"; }

void
TOleDocWindow::GetWindowClass(WNDCLASS _FAR &wc )


{



TWindow::GetWindowClass(
wc );


wc.lpszMenuName
= "MENU_DOCWINDOW";


}

void
TOleDocWindow::CMClear( RTMessage )


{



CloseCurrentOle();


}

void
TOleDocWindow::CloseCurrentOle()


{


//
окончательное
сохранение


if
( lpObject ) {


ret
= OleDelete( lpObject );


wait(
ret , lpObject );


}


if
( lpUndoObject ) {


ret
= OleDelete( lpUndoObject );


wait(
ret , lpObject );


}


lpObject
= lpUndoObject = NULL;

bObjectLoaded
= FALSE;

InvalidateRect(
HWindow , NULL, TRUE );


UpdateWindow(
HWindow );


}

void
TOleApp::InitMainWindow()


{


MainWindow
= new TOleDocWindow(NULL, "OWL OLE Application" );


}

int
PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,



LPSTR lpCmd, int
nCmdShow)


{


TOleApp
OleApp ("OleApp", hInstance, hPrevInstance,


lpCmd,
nCmdShow);


OleApp.Run();


return
(OleApp.Status);


}

Сохранить в соц. сетях:
Обсуждение:
comments powered by Disqus

Название реферата: Протоколы и стандарты объектно-ориентированного программирования

Слов:16702
Символов:91989
Размер:179.67 Кб.