Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:OC Windows & OC Linux. Лабораторные работы по курсу «Операционные системы»
.pdf
В приведенном выше примере в разделе EXPORTS перечислены имена нескольких экспортируемых функций. Около некоторых
имен после символа @ указаны порядковые номера соответствующих функций в DLL-библиотеке.
Если вы не укажете порядковые номера экспортируемых функций, при компоновке загрузочного файла DLL-библиотеки редактор
связи создаст свою собственную нумерацию, которая может изменяться при
следующей повторной компоновке.
Если при помощи файла определения модуля DLL-библиотеки
вы задаете фиксированное распределение порядковых номеров экспортируемых функций, при внесении изменений в исходные тексты
DLL-библиотеки это распределение не изменится. В этом случае все
приложения, ссылающиеся на функции из этой библиотеки по
порядковым номерам, будут работать правильно. Если же вы не определили порядковые номера функций, у приложений могут возникнуть проблемы с правильной адресацией функции из-за возможного
изменения этих номеров.
1.3.5. Импортирование функций
Когда вы используете статическую компоновку, то включаете в
файл проекта приложения соответствующий lib-файл, содержащий
нужную вам
держит исполняемый код модулей, который на этапе статической
компоновки включается в ехе-файл загрузочного модуля.
Если используется динамическая компоновка, в загрузочный
ехе-файл приложения записывается не исполнимый код функций, а
ссылка на соответствующую DLL-библиотеку и функцию внутри
нее. Как мы уже говорили, эта ссылка может
использованием либо имени функции, либо ее порядкового номера в
DLL-библиотеке.
С помощью оператора IMPORT можно перечислить импортируемые функции, указав имена функций или их порядковые номера,
а также имена файлов соответствующих DLL-библиотек:
IMPORTS
Msg=dllsrc.4
dllsrc.TelIMe
внесении изменений в исходные тексты функций и по-
их
библиотеку объектных модулей. Такая библиотека со-
быть организована с
61

Во второй строке приведенного выше примера приложение импортирует функцию Msg из DLL-библиотеки dllsrc.dll, причем порядковый номер указанной функции в библиотеке равен 4.
В третьей строке из DLL-библиотеки dllsrc.dll импортируется
функция с именем TelIMe, причем ее порядковый номер не используется.
Для увеличения скорости работы приложения рекомендуется
использовать способ, основанный на ссылке по имени DLL-библи
отеки и порядковому номеру функции внутри этой библиотеки.
1.3.6. Файл определения модуля для DLL-библиотеки
Файл определения модуля для DLL-библиотеки отличается от
соответствующего файла обычного приложения Windows. В качестве примера приведем образец такого файла:
LIBRARY DLLNAME
DESCRIPTION 'DLL-библиотека DLLNAME'
EXETYPE windows
CODE moveable discardable
DATA moveable single
HEAPSIZE 1024
EXPORTS
DrawBitmap @4
ShowAll
HideAll
GetMyPool @8
FreeMyPool @9
В файле определения модуля DLL-библиотеки вместо оператора NAME должен находиться оператор LIBRARY, определяющий
имя
модуля DLL-библиотеки, под которым она будет известна Win-
dows.
Остальные операторы те же, что и для обычного приложения, за
исключением того, что в файле определения модуля DLL-библиотеки не должно быть оператора STACKSIZE (так как у DLL-библиотеки нет стека).
Оператор CODE используется для определения атрибутов сегмента кода DLL-библиотеки.
-
62

Особенностью оператора DATA является использование параметра SINGLE. Так как DLL-библиотека находится в памяти в единственном экземпляре и может иметь только один сегмент данных,
для описания сегмента данных библиотеки требуется параметр
SINGLE. Оператор HEAPSIZE определяет начальное значение локальной области памяти, которая будет выделена для DLL-библиотеки функцией LibEntry на этапе инициализации. Если DLL-библиотека не должна иметь локальную область данных, в качестве параметра следует указать нулевое значение:
HEAPSIZE 0
И, наконец, оператор EXPORTS предназначен для перечисления
имен и порядковых номеров функций, экспортируемых DLL-библиотекой.
З
АДАНИЯ НА РАБОТУ
Задание 1. Создать собственную библиотеку динамической ком-
поновки DLL, содержащую функцию из лабораторной работы № 1
Задание 2. Написать программу для вызова функции, расположенной в DLL-библиотеке, созданной в задании 1 и показывающей
работу этой функции.
63

ЛАБОРАТОРНАЯ РАБОТА № 5
ОБМЕН ДАННЫМИ ЧЕРЕЗ DDE
Введение
Операционная система Windows предоставляет пользователю
возможность запустить одновременно несколько приложений. Как
правило, пользователь именно так и поступает. Однако сама по себе
эта достаточно важная особенность Windows не имела бы столь
большого значения, если бы не существовали удобные механизмы
обмена данными между приложениями.
Цель работы: ознакомить
студентов с механизмом динамического обмена данными DDЕ (Dynamic Data Exchange), позволяющим
создавать постоянно действующие каналы между несколькими одновременно работающими приложениями Windows.
О
ПИСАНИЕ РАБОТЫ
Начиная с версии 3.1 в составе Windows появилось расширение –
управляющая библиотека динамического обмена данными DDEML,
выполненная как обычная DLL-библиотека. При создании новых
DDЕ-приложений в SDK рекомендуется пользоваться именно этой
библиотекой, а не старым механизмом, основанным на передаче сообщений. Библиотека DDEML хороша сама по себе, так как она упрощает DDЕ-приложения и избавляет
программиста от учета утомительных деталей протокола обмена сообщениями. Однако есть еще
две причины, по которым следует пользоваться этой библиотекой.
Во-первых, в новых версиях Windows, а также в операционной
системе Windows NT динамический обмен данных организуется исключительно с помощью библиотеки DDEML. Поэтому если в будущем вы собираетесь переносить свое приложение в
среду Windows NT или Windows-95, имеет смысл сразу ориентироваться на
работу с DDEML.
Во-вторых, вспомним о существовании такой операционной
системы, как Windows for Workgroups. Сетевые возможности Windows for Workgroups базируются на сетевом динамическом обмене
данными Network DDE (операционная система Windows NT также
поддерживает Network DDE).
Механизм Network DDE позволяет организовать каналы обмена
данными между приложениями, которые запущены на разных рабо-
64

чих станциях сети. Поэтому освоение «обычной» библиотеки
DDEML можно считать первым шагом на пути к изучению сетевых
возможностей различных версий Windows.
1.1. Архитектура «клиент – сервер»
Клиентом и сервером мы будем называть процессы (программы или приложения), работающие одновременно на одном или разных компьютерах (объединенных в сеть), и взаимодействующих
между собой определенным
Клиент посылает серверу запрос на получение данных или выполнение какой-либо работы. Это может быть запрос к серверу базы
данных, задание серверу резервного копирования дисков или что-то
аналогичное.
Сервер, получив от клиента запрос, выполняет соответствующие действия и посылает клиенту ответ. Например, сервер базы
данных находит нужные записи
зервного копирования вводит в действие механизм выгрузки данных
на магнитную ленту или магнитооптическое дисковое устройство и
сообщает клиенту о запуске процедуры.
Процесс передачи запроса серверу называется транзакцией.
Строго говоря, транзакция – это совокупность трех дейст-
вий: посылка запроса, выполнение запроса, прием ответа.
Транзакция называется завершенной
действия. Если же на одном из трех этапов произошел сбой, транзакция останется незавершенной. После восстановления незавершенная транзакция откатывается, что необходимо в ряде случаев
для сохранения целостности данных (разумеется, за правильное выполнение отката транзакции отвечает сервер).
Например, если сервер базы данных получил от клиента
на обновление записей в нескольких файлах и перед аварийным отключением электропитания успел выполнить только часть работы,
после восстановления ему необходимо восстановить состояние базы
данных на момент начала незавершенной транзакции.
Топология системы, имеющей архитектуру «клиент – сервер»,
может быть различной. В системе может быть несколько клиентов,
работающих с одним сервером, или
щих одновременно с несколькими серверами.
Приложения, использующие технологию динамического обмена
данных DDE, выступают как клиенты или серверы (или одновре-
образом.
и посылает их клиенту. Сервер ре-
, если выполнены все три
запрос
несколько клиентов, работаю-
65

менно как клиенты и серверы). При этом взаимодействие между ними – это ни что иное, как транзакции.
Библиотека DDEML позволяет создавать системы, имеющие
различные топологии.
1.2. Инициализация и создание канала связи
Предположим, что нам нужно создать канал связи между двумя
одновременно работающими приложениями Windows. Опишем соответствующие процедуры при использовании библиотеки DDEML.
Пусть одно
клиентом.
В процессе инициализации сервер должен выполнить такие
действия:
– зарегистрировать себя в библиотеке DDEML;
– зарегистрировать предоставляемый сервис, которым сможет вос-
пользоваться приложение-клиент.
Клиент должен сделать следующее:
– зарегистрировать себя в библиотеке DDEML;
– создать канал связи с сервером, указав необходимый сервис.
Рассмотрим эти
1.2.1. Регистрация в библиотеке DDEML
Библиотека DDEML используется одновременно многими приложениями, однако, подобно всем DLL-библиотекам, находится в
оперативной памяти в единственном экземпляре. Функция LibMain,
выполняющая инициализацию DLL-библиотеки, вызывается только
один раз при первой загрузке библиотеки в память (для Windows
версии 3.1), поэтому LibMain не может использоваться для регистрации приложений.
Если приложение собирается использовать
но зарегистрировать себя в библиотеке DDEML, вызвав специально
предназначенную для этого функцию с именем DdeInitialize.
Прототип функции DdeInitialize определен в файле ddeml.h (который должен быть включен в исходный текст DDEML-приложения
наряду с файлом windows.h):
UINT WINAPI DdeInitialize (
DWORD FAR* pidInst, // адрес идентификатора
из этих двух приложений будет сервером, а другое –
действия подробнее.
DDEML, оно долж-
приложения
66

PFNCALLBACK pfnCallback, // адрес функции
обратного вызова
DWORD afCmd, // флаги
DWORD ulRes); // зарезервировано
Функция DdeInitialize используется в процессе инициализации и
серверов, и клиентов DDEML. Сама по себе она не создает никаких
каналов передачи данных между приложениями, однако процедура
регистрации приложения, выполняемая этой функцией, должна быть
проведена до вызова любых других функций, имеющих отношение к
DDEML.
Параметр pidInst представляет собой
во, в которое после регистрации будет записан идентификатор, присвоенный копии приложения библиотекой DDEML (одновременно
могут работать несколько копий одного и того же DDЕМL-приложения). Иными словами, в процессе регистрации библиотека DDEML
присваивает копии приложения некоторый идентификатор, под которым она его «знает». Вы должны указывать полученный от
ции идентификатор при вызове всех остальных функций библиотеки
DDEML.
Перед вызовом функции DdeInitialize ваше приложение должно
записать в двойное слово, адрес которого передается через первый
параметр, нулевое значение.
Заметим, что идентификатор копии приложения, присвоенный в
процессе регистрации, и идентификатор копии приложения, полученный через параметр функции WinMain, – разные по смыслу (и по
значению) идентификаторы.
Параметр pfnCallback представляет собой указатель на функцию
обратного вызова, определенную приложением для обработки транзакций. Как сервер, так и клиент должны определить такую функцию. Функция обратного вызова вызывается системой DDEML и
содержит в себе всю логику обработки транзакций, определенную
вами при разработке приложения.
Если приложение вызывает функцию DdeInitialize несколько
раз
для многократной регистрации, каждый раз следует указывать
отдельную функцию обратного вызова. Многократная регистрация
вполне допустима, так как каждый раз библиотека DDEML будет
создавать для себя новый идентификатор приложения. Такая методика используется при создании DLL-библиотек, работающих с
DDEML. Обычным приложениям достаточно зарегистрировать себя
67
указатель на двойное сло-
функ-

один раз и, соответственно, определить одну функцию обратного
вызова.
Через параметр afCmd передается двойное слово, каждый бит
которого является флагом, определяющим режимы работы канала
связи, а также влияющие на действия, выполняемые функцией
DdeInitialize.
Последний параметр с именем ulRes зарезервирован и должен
иметь нулевое значение.
Приведем фрагмент кода, выполняющего регистрацию сервера
в библиотеке DDEML:
idInst = 0L;
lpDdeSrProc = MakeProcInstance((FARPROC)DDEServerCallback, hInst);
if(DdeInitialize( (LPDWORD)&idInst, (PFNCALLBACK)lpDdeSrProc,
APPCLASS_STANDARD, 0L))
{
return FALSE;
}
В этом фрагменте вначале создается переходник для функции
обратного вызова, затем адрес этого переходника указывается во
втором параметре функции DdeInitialize.
В случае успеха функция DdeInitialize возвращает нулевое
значение. Для проверки можно также использовать константу
DMLERR_NO_ERROR, определенную в файле ddeml.h. Если произошла ошибка, возвращается ненулевой код ошибки. Соответствующие константы определены
имени DMLERR.
Символические константы с префиксом имени APPCLASS позволяют задать класс приложения с точки зрения использования
DDEML.
Класс APPCLASS_STANDARD предназначен для регистрации
стандартного DDЕМL-приложения. Класс APPCLASS_MONITOR
предназначен для отладчиков и других приложений, управляющих
работой системы DDEML.
Символические константы с префиксом имени APPCMD позволяют конкретизировать функции, выполняемые приложением,
и экономить
системные ресурсы. Если DDЕМL-приложение вы-
в файле ddeml.h и имеют префикс
68

полняет только функции клиента, следует указать флаг
APPCMD_CLIENTONLY:
if(DdeInitialize((LPDWORD)&idInst,
(PFNCALLBACK)lpDdeClProc,
APPCMD_CLIENTONLY, 0L))
{
return NULL;
}
В простейших случаях можно ограничиться использованием
класса APPCLASS_STANDARD при создании сервера DDEML и
флага APPCMD_CLIENTONLY при создании клиента DDEML.
Если приложение больше не собирается работать с библиотекой
DDEML, оно должно вызвать функцию DdeUninitialize, передав ей в
качестве единственного параметра идентификатор копии приложения, полученный от функции DdeInitialize:
BOOL WINAPI DdeUninitialize(DWORD idInst);
1.2.2. Регистрация сервиса
Следующий этап в инициализации сервера DDEML заключается в регистрации предоставляемого им сервиса.
Библиотека DDEML использует трехступенчатую схему адресации данных, передаваемых по каналу связи, – сервис (service), раздел (topic) и элемент данных (data item). Приложение задает элементы адреса в виде текстовых строк размером не более 255 байт. Это
ограничение возникло в результате
DDEML атомов, которые представляют собой идентификаторы текстовых строк, хранящихся в специальной системной таблице. Размер
таких строк не должен превышать 255 байт.
Сервер DDEML может предоставлять сервис одного или нескольких видов. Как правило, один сервер предоставляет только
один сервис, причем текстовая строка, идентифицирующая сервис,
часто совпадает с именем приложения.
другую строку. Например, наше приложение DDEMLSR предоставляет сервис «BMPService». Как можно догадаться из названия, этот
сервис связан с bmр-файлами (в действительности мы привели сильно упрощенную версию сервера bmр-файлов, в которой для сокра-
использования для реализации
Но можно выбрать любую
69

щения объема листингов изъяты функции обслуживания bmрфайлов.
Второй элемент адреса – раздел. В рамках одного сервиса можно определить несколько разделов. Когда клиент DDEML создает
канал с сервером, он указывает сервис и раздел. Раздел объединяет
группу элементов данных или выполняемых функций. В приложении DDEMLSR определен один раздел «BMPFile».
Канал DDEML служит для передачи блоков
одного раздела сервер может обмениваться с клиентом разными
блоками данных, каждый из которых идентифицируется при передаче именем элемента данных. В процессе создания канала связи не
требуется указывать элементы данных.
Регистрация сервиса выполняется сервером DDEML обычно
сразу после вызова функции DdeInitialize и выполняется в два этапа.
На первом этапе
специальной системной таблице (таблице атомов), для чего вызывается функция DdeCreateStringHandle:
HSZ WINAPI DdeCreateStringHandle(
DWORD idInst, // идентификатор приложения
LPCSTR psz, // адрес текстовой строки
int iCodePage); // кодовая страница
Через параметр idInst приложение должно передать идентификатор, полученный на этапе регистрации приложения в библиотеке
DDEML функцией DdeInitialize.
Параметр psz представляет собой указатель на текстовую строку, закрытую двоичным
вышать 255 байт.
В качестве значения для параметра iCodePage можно указать
СР_WINANSI (эта константа равна нулю). Можно также использовать значение, полученное от функции GetKBCodePage. Функция
GetKBCodePage не имеет параметров и возвращает номер текущей
кодовой страницы.
Идентификатор текстовой строки, возвращенный функцией
DdeCreateStringHandle и соответствующий регистрируемому сервису,
следует передать функции DdeNameService:
НDDЕDАТА WINAPI DdeNameService(
DWORD idInst, // идентификатор приложения
текстовая строка имени сервиса сохраняется в
нулем. Размер этой строки не должен пре-
70
данных. В рамках
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
