- •Лабораторные работы по курсу «Современные технологии и инструментарий программирования»
- •1. Разработка и использование «обычных» библиотек dll (cui)
- •1.1.Бесценные методические приказания
- •2.Разработка и использование dll-расширения
- •Ознакомиться с теоретической частью работы, для чего придется изучить раздел конспекта «Разработка и использование собственных dll», особенно подраздел «Основы dll».
- •2.1.Разработка библиотеки-расширения
- •2.2.Разработка клиентского приложения для dll-расширения
- •3.Разработка внутрипроцессного сервера и клиентского приложения с использованием atl
- •Часть 1. Разработка простого внутрипроцессного сервера сом, реализованного в виде библиотеки dll
- •Interface iMathem2; // добавлено
- •Часть 2. Разработка клиентского консольного приложения для тестирования внутрипроцессного сервера сом
- •4.Разработка и использование локального сервера
- •Часть 1. Разработка локального сервера сом
- •Часть 2. Разработка клиентского приложения для локального сервера сом
- •Литература
- •7. Проект New_Syntax
- •8. Руководство_по_c#.Doc
3.Разработка внутрипроцессного сервера и клиентского приложения с использованием atl
Число студентов в бригаде имеет тенденцию возрастать независимо от объема лабораторной работы, которую надо выполнить
Наблюдение в ХАИ
Цель работы – освоить разработку и использование простого СОМ объекта, реализованного в виде внутрипроцессного сервера (библиотеки DLL), и клиентского консольного приложения (4 час. на одного человека или 180мин./число_членов_бригады).
Задание. В первой части работы описан сценарий создания внутрипроцессного сервера. В СОМ объекте этого сервера требуется реализовать по крайней мере два интерфейса и в первом из них – минимум два метода, а во втором – по крайней мере один. Реализуемые методы и решаемую задачу выбрать по своему усмотрению, если, конечно, вы не хотите показаться обезьянкой, которая просто кому-то подражает. Также надо снабдить СОМ объект каким-нибудь свойством для чтения и записи.
Обязательные требования к реализуемым методам:
Метод должен возвращать значение через один из своих параметров.
Минимум один из методов должен получать в качестве параметра массив, выполнять над ним какое-нибудь нетривиальное действие и возвращать результат посредством параметра. Число элементов массива также надо передавать этому методу через параметр или через свойство.
Во второй части работы изложен сценарий создания клиентского приложения, которое предлагается реализовать в виде консольного приложения с поддержкой MFC.
Часть 1. Разработка простого внутрипроцессного сервера сом, реализованного в виде библиотеки dll
Методические указания. Последовательность создания простого COM сервера в MVS-2008 с использованием ATL (Active Template Library – библиотека активных шаблонов) состоит из следующих основных этапов:
создание каркаса приложения-библиотеки с помощью мастера ATL Project;
создание СОМ объекта с фабрикой классов с помощью мастера ATL Simple Object;
добавление в СОМ объект интерфейсов, объявлений методов и их реализаций;
построение и регистрация (в реестре Windows) СОМ объекта, реализованного в виде внутрипроцессного сервера, т.е. DLL-библиотеки.
Шаг 1. Создание каркаса внутрипроцессного сервера.
Так как в этой работе нам надо будет создать два приложения – внутрипроцессный сервер и клиентское приложение – рекомендую создать для них общую папку с именем, например, Lab5 и в этой папке создавать проекты, каждый из которых, в свою очередь, будет размещаться в отдельной папке.
Выполнить тему меню FileNewProject. Как и при разработке любого другого приложения, в появившемся окне необходимо задать путь к проекту в поле ввода Location (…\Lab5) и имя проекта DLLMathServer в поле ввода Name. Выберите Project types=ATL и Templates=ATL Project, нажмите ОК.
На следующей странице Application Settings выберите только переключатель Server type=Dynamic-link library и не выбирайте никаких опций в группе Additional options, хотя это и не существенно для данного приложения. Впрочем, это только рекомендация: вы можете делать все что угодно, если любите преодолевать трудности. Нажмите кнопарек Finish – хотя это еще отнюдь не финиш, а пока просто завершение создания каркаса приложения.
Вам разрешается, совершенно безвозмездно, т.е. даром, посмотреть на файлы, сгенерированные мастером: DLLMathServer.cpp и DLLMathServer.def. Во втором файле (DLLMathServer.def) вы обнаружите, что библиотека экспортирует – по собственной инициативе – четыре важные функции:
DllCanUnloadNow();
DllGetClassObject();
DllRegisterServer() и
DllUnregisterServer().
Назначение этих функций подсказывают их имена. Интерес представляет также файл DLLMathServer.idl, к содержимому которого мы еще будем обращаться. В этом файле будет содержаться описание СОМ объекта и его методов на языке описания интерфейсов (IDL – interface definition language).
Шаг 2. Включение в библиотеку COM-объекта.
Выполните команду ProjectAdd class. В появившемся окне надо выбрать Categories==ATL (не выбирайте WMI) и Templates==ATL Simple Object и нажать кнопку Add. В следующем окне на вкладке Names достаточно ввести только короткое имя объекта в поле Short name, а остальные имена мастер сгенерирует сам и их можно не изменять. В данном примере для объекта выбрано имя Mathem (рис. 1).
|
Рис.1. Задание свойств СОМ объекта
Естественно, вы обратили внимание на то, что мастер все остальные имена сформировал по короткому (Mathem) имени СОМ объекта. В частности, обратите внимание на поле ProgID: это так называемое внешнее имя СОМ сервера, под которым он будет зарегистрирован в реестре и которое можно будет использовать в клиентских приложениях для идентификации СОМ сервера. Естественно, что вы можете изменить имена, сформированные мастером, но … стоит ли это делать?
Нажмите кнопку Next или, что-то же самое, перейдите к вкладке Options. На этой вкладке выберите Threading model==Single и Interface==Custom. Оставьте остальные установки мастера без изменения и натисните Finish. Наберитесь терпения и дождитесь, когда мастер завершит создание заготовки СОМ объекта.
После работы этого мастера появятся два (основных) новых файла: Mathem.h и Mathem.cpp. Файл Mathem.h содержит объявление сокласса CMathem, включающего интерфейс «по умолчанию» IMathem и пустой конструктор класса. Файл реализации класса Mathem.cpp вообще пока будет пустым. Обратите внимание на «родителей» класса CMathem (файл Mathem.h): вам понятно, кто они по происхождению? Что указано в угловых скобках?
Таким образом, мы имеем заготовку сервера и (одного) СОМ-объекта в нем. Проект можно компилировать и собрать, получить библиотеку DLL (внутрипроцессный сервер), но никакого полезного кода он пока не содержит. Надо собрать волю в кулак, напрячь (или напрясть?) свой могучий интеллект, объявить и реализовать какие-либо методы (и/или свойства) СОМ объекта.
Шаг 3. Добавление метода в СОМ объект.
Для
добавления метода надо выбрать вкладку
ClassView в окне решений, в ней выбрать
ветвь DLLMathServer (а не DLLMathServerPS)
и в ней первую подветвь IMathem,
помеченную значком интерфейса
.
Вызвав контекстное меню для IMathem,
выберите команду AddAdd
method для добавления
метода к интерфейсу IMathem.
В появившемся окне (рис. 2) надо объявить
метод. Допустим, что мы хотим реализовать
такой ценный (или бесценный?) метод:
HRESULT Cube(double Arg, double *Res)
{
*Res=Arg*Arg*Arg;
return S_OK;
}
Метод может возвращать значение только типа HRESULT (целое 32-битовое число, содержащее результат выполнения метода – код ошибки), а практический результат, в данном случае куб аргумента, мы будем возвращать посредством параметра-указателя Res.
|
Рис. 2. Окно мастера добавления метода в интерфейс
Тогда в окне мастера добавления метода мы должны выполнить такие действия:
в поле Method name ввести имя метода Cube;
включить флажок in (входной параметр) в Parameter attributes;
в списке Parameter type выбрать имя типа DOUBLE;
в поле Parameter name ввести имя первого параметра функции Arg;
нажать кнопку Add, завершив тем самым ввод объявления первого параметра функции;
в списке Parameter type выбрать имя типа второго параметра DOUBLE*;
включить флажок out (выходной параметр) в Parameter attributes;
в поле Parameter name ввести имя второго параметра функции Res;
шлепнуть по кнопке Add.
В результате этих манипуляций окно мастера должно приобрести вид, который и представлен на рис. 2. На вкладке IDL Attributes ничего изменять не нужно. Конечно, не мешало бы ввести информативное описание метода в поле helpstring перед ударом по кнопке Finish (описание можно и не вводить, если у вас есть чудодейственное зелье от проклятий пользователя метода). Подробное описание атрибутов метода имеется в MSDN и вы сможете его улицезреть, если нажмете клавишу F1 или символ ? в правом верхнем углу окна мастера.
Объявление метода будет шустренько добавлено в тело класса CMathem (файл Mathem.h), а заготовка для его определения – в файл реализации Mathem.cpp, куда вы и должны добавить тело метода, приведенное выше. В результате определение метода должно принять такой законченный вид:
STDMETHODIMP CMathem::Cube(DOUBLE Arg, DOUBLE* Res)
{
*Res=Arg*Arg*Arg;
return S_OK;
}
Если побродить по заголовочным файлам, то можно обнаружить, что макрос STDMETHODIMP в конечном итоге приводит заголовок метода к такому виду:
long __stdcall CMathem::Cube(DOUBLE Arg, DOUBLE* Res)
Настоятельно рекомендую ознакомиться с содержимым файла DLLMathServer.idl, который содержит практически полное описание нашего СОМ объекта на Interface Definition Language (IDL) – языке описания интерфейсов. Сие значит, что там объявлен интерфейс IMathem и предоставляемый им пока единственный метод Cube().
Выполните компиляцию и сборку приложения, в результате чего в каталоге Debug (при установке отладочной конфигурации в качестве активной) должен появиться файл DLLMathServer.dll, который и будет содержать земную материализацию внутрипроцессного сервера.
Замечание 1. Ежели при компиляции здесь и далее пред Вашим ясным взором вдруг возникнет окно с сообщением, содержащим текст «This file has been modified outside of the source editor. Do you want to reload it?» – поверьте ИС и шмякните по кнопке «Yes to All»
Если вы обратитесь к анализу содержимого реестра Windows, то уже на этом этапе обнаружите там информацию о вашем сервере (например, поищите имя DLLMathServer.Mathem).
Замечание 2. Для регистрации сервера в реестре у вас должны быть права на запись в разделы реестра HKEY_CLASSES_ROOT и HKEY_LOCAL_MACHINE. Зарегистрировать сервер в реестре можно также с помощью команды «RegSvr32.exe имя_сервера», где имя_сервера должно быть полным именем приложения, включающим путь. Разрегистрировать приложение можно с помощью команды «RegSvr32.exe /u имя_сервера».
Итак, на сием этапе мы получили СОМ объект с пока еще одним интерфейсом IMathem. Обратите внимание также на внешнее имя программы (библиотеки) DLLMathServer.Mathem, указанное в окне Prog ID (см. рис.1), которое нам понадобится при разработке клиентского приложения. Это имя, к слову сказать, указывается в реестре Windows как значение ключа VersionIndependentProgID, а значением ключа ProgID будет DLLMathServer.Mathem.1. Более подробные сведения о том, какие записи в реестре появляются при регистрации сервера, см. в конспекте (подразд. «О регистрации внутрипроцессного сервера СОМ» раздела «Приложения»).
Подведем промежуточные итоги. На этой стадии разработки проекта создана DLL-библиотека, которая является «домом» для нашего СОМ-объекта, и сам СОМ-объект, который имеет один интерфейс и один метод. В файле определения модуля DLLMathServer.def перечислены функции, которые экспортирует наша библиотека. Расслабтесь: вам не придется заниматься реализацией этих пяти стандартных для СОМ-серверов функций, хотя делать это и не запрещено.
Шаг 4. Добавление в СОМ-объект еще одного интерфейса.
Расслабились? Теперь сосредоточтесь. Для добавления нового интерфейса к существующему СОМ объекту необходимо открыть файл библиотеки типов (DLLMathServer.idl) и скопировать описание первого интерфейса, т.е. создать копию следующих строк файла DLLMathServer.idl:
[
object,
uuid(2E4FB046-98D8-4E74-8572-84D7133FFEF4),
pointer_default(unique)
]
interface IMathem : IUnknown{
[] HRESULT Cube([in] DOUBLE Arg, [out] DOUBLE* Res);
};
Эти скопированные строки надо разместить непосредственно ниже оригинальных.
Далее необходимо изменить имя интерфейса (в данном примере я выбрал имя IMathem2), удалить строку с описанием метода Cube и заменить идентификатор uuid на новый, воспользовавшись командой ToolsCreate Guid. В окне мастера генерации uuid проще всего выбрать четвертый формат представления уникального идентификатора (Registry uuid). Кроме того, новый интерфейс необходимо добавить в описание сокласса (coclass Mathem), но уже без спецификатора default, так как только один интерфейс может быть интерфейсом по умолчанию. В результате этих действий содержимое файла библиотеки DLLMathServer.idl должно стать таким (комментарии в начале файла опущены, а добавленные строки выделены цветом и комментариями. Копировать текст нельзя, так как идентификаторы uuid должны быть уникальными):
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(2E4FB046-98D8-4E74-8572-84D7133FFEF4),
pointer_default(unique)
]
interface IMathem : IUnknown{
[] HRESULT Cube([in] DOUBLE Arg, [out] DOUBLE* Res);
};
// начало добавлений
[
object,
uuid(EE0BAF52-B2DB-4CC7-BD5E-9DB352699F3F),
pointer_default(unique)
]
interface IMathem2 : IUnknown{
};
// конец добавлений
[
uuid(946AB57D-27B2-480A-B3A9-D90E2398D356),
version(1.0),
]
library DLLMathServerLib
{
importlib("stdole2.tlb");
[
uuid(DA4D3129-504E-4E42-AE02-BCBB9771118C)
]
coclass Mathem
{
[default] interface IMathem;
