Разработка и использование «обычных» библиотек DLL (CUI)

Разработка и использование «обычных» библиотек DLL (CUI)

Есть моменты, когда все удается. Не ужасайтесь, это пройдет

Закон Мерфи

Цель работы – освоение технологии разработки и использования «обычных» библиотек DLL (Regular DLL using shared MFC DLL). В рамках этой работы мы построим обычную DLL-библиотеку, экспортирующую одну-единственную функцию. Далее надо разработать простое клиентское приложение, использующее эту библиотеку. Таким образом, мы получим аж два приложения – и все это за 2 час. с перекурами!

Задание. Рекомендуемая последовательность выполнения работы:

1. Ознакомиться с теоретической частью работы, для чего придется изучить раздел конспекта «Разработка и использование собственных DLL», особенно подраздел «Основы DLL».

2. Создать обычную (regular) библиотеку DLL, экспортирующую не класс, а просто одну или несколько функций.

3. Создать клиентское приложение, использующее разработанную библиотеку.

Разработка и использование DLL-расширения

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

Фредерик Брукс-младший

Цель работы – освоение технологии разработки и использования DLL-расширений (MFC Extension DLL). В рамках этой работы мы построим библиотеку DLL-расширение, которая будет экспортировать класс CGraphic, предназначенный для построения графика любой (одномерной) функции. Далее надо разработать простое клиентское приложение, использующее эту библиотеку (2 час.).

Задание. Рекомендуемая последовательность выполнения работы:

1. Ознакомиться с теоретической частью работы, для чего придется изучить раздел конспекта «Разработка и использование собственных DLL», особенно подраздел «Основы DLL».

2. Создать библиотеку DLL-расширение, экспортирующую некоторый класс.

3. Создать клиентское приложение, подключив к нему библиотеку DLL-расширение. Это приложение будет создавать объект класса, тип которого описан в библиотеке.

Class CGraphic

на следующую

class AFX_EXT_CLASS CGraphic

Макрос AFX_EXT_CLASS намекает на то, что этот класс экспортируется библиотекой. Клиентское приложение, использующее библиотеку, тоже должно в соответствующем заголовочном файле (Graphic.h) содержать этот макрос.

Шаг 6. Постройте библиотеку с помощью команды меню BuildèBuild ExtDLL.dll.

В папке …\ExtDLL\Debug вы должны обнаружить файлы ExtDLL.dll и ExtDLL.lib. Если их там нет, значит, они были съедены вирусами, которым очень нравятся библиотеки.

Разработка внутрипроцессного сервера и клиентского приложения с использованием ATL

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

Наблюдение в ХАИ

Цель работы – освоить разработку и использование простого СОМ объекта, реализованного в виде внутрипроцессного сервера (библиотеки DLL), и клиентского консольного приложения (4 час. на одного человека или 180мин./число_членов_бригады).

Задание. В первой части работы описан сценарий создания внутрипроцессного сервера. В СОМ объекте этого сервера требуется реализовать по крайней мере два интерфейса и в первом из них – минимум два метода, а во втором – по крайней мере один. Реализуемые методы и решаемую задачу выбрать по своему усмотрению, если, конечно, вы не хотите показаться обезьянкой, которая просто кому-то подражает. Также надо снабдить СОМ объект каким-нибудь свойством для чтения и записи.

Обязательные требования к реализуемым методам:

1. Метод должен возвращать значение через один из своих параметров.

2. Минимум один из методов должен получать в качестве параметра массив, выполнять над ним какое-нибудь нетривиальное действие и возвращать результат посредством параметра. Число элементов массива также надо передавать этому методу через параметр или через свойство.

Во второй части работы изложен сценарий создания клиентского приложения, которое предлагается реализовать в виде консольного приложения с поддержкой MFC.

Object,

Uuid(2E4FB046-98D8-4E74-8572-84D7133FFEF4),

pointer_default(unique)

]

interface IMathem : IUnknown{

[] HRESULT Cube([in] DOUBLE Arg, [out] DOUBLE* Res);

};

Эти скопированные строки надо разместить непосредственно ниже оригинальных.

Далее необходимо изменить имя интерфейса (в данном примере я выбрал имя IMathem2), удалить строку с описанием метода Cube и заменить идентификатор uuid на новый, воспользовавшись командой ToolsèCreate 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(946AB57D-27B2-480A-B3A9-D90E2398D356),

Version(1.0),

]

Library DLLMathServerLib

{

importlib("stdole2.tlb");

[

Uuid(DA4D3129-504E-4E42-AE02-BCBB9771118C)

]

Coclass Mathem

{

[default] interface IMathem;

Public IMathem,

CMathem()

{

}

DECLARE_REGISTRY_RESOURCEID(IDR_MATHEM)

DECLARE_NOT_AGGREGATABLE(CMathem)

BEGIN_COM_MAP(CMathem)

COM_INTERFACE_ENTRY(IMathem)

COM_INTERFACE_ENTRY(IMathem2) // добавлено

END_COM_MAP()

После этих модификаций библиотека должна компилироваться и собираться без ошибок – поверьте, но проверьте!

Шаг 5.Добавление новых методов и свойств.

Для добавления новых методов необходимо действовать так же, как и при добавлении методов к интерфейсу по умолчанию (см. инструкции к шагу 3). Возможно, что реализацию методов нового интерфейса придется добавлять вручную в файл реализации Mathem.cpp. Также, очевидно, надо будет добавить объявление (прототип) новых методов в заголовочный файл Mathem.h по аналогии с методами первого интерфейса.

Самостоятельно выберите какой-нибудь метод, обрабатывающий массив, и добавьте его в интерфейс IMathem2. Параметр-массив надо объявлять как указатель, например, LONG *, CHAR * или DOUBLE *, так как методы СОМ объектов не поддерживают параметры структурных типов. Добавьте также еще один метод к любому интерфейсу и свойство (property). Тип свойства опять-таки выберите по своему усмотрению, напишите реализацию методов установки и чтения значения свойства. Для хранения значения свойства добавьте в класс CMathem член-переменную для достижения этой возвышенной цели.

В качестве примера полезного метода рассмотрим такую задачу. Во многих инженерных расчетах используются исходные данные, заданные таблично. Например, на рис. 3 приведена иллюстрация метода использования таблично-заданной функции Y(X) для получения значения функции YK для заданного значения аргумента XK.

 
  Разработка и использование «обычных» библиотек DLL (CUI) - student2.ru

Рис. 3. Интерполяция таблично-заданных значений функции Y(X)

Для знающего математику даже в объема школьного курса понятно, что в качестве исходных данных надо иметь:

· массив значений функции Y;

· массив значений аргумента функции X;

· значение аргумента Xk, для которого требуется определить значение функции Yk.

Также совершенно очевидно, что задача определения Yk по Xk сводится к линейной интерполяции значений функции на известном отрезке Xi<=Xk<=Xi+1, что также не выходит за рамки начальных знаний геометрии на плоскости.

Этот пример метода не только полезный, но и необходимый для реализации в вашем сервере.

При добавлении в интерфейс свойства с помощью мастера (последовательность действий такая же, как и для метода) в окне Add Property Wizard достаточно указать только тип свойства (выбрать в списке Property type) и ввести его имя (поле Prpoperty name). Больше ничего вводить или изменять в данном случае не нужно. Например, если задать имя свойства Foo и выбрать для него тип BSTR, то в файле DLLMathServer.idl появятся строки, выделенные полужирным шрифтом:

interface IMathem : IUnknown{

[helpstring("method Cube")] HRESULT Cube([in] DOUBLE Arg,

[out] DOUBLE* Res);

[propget, helpstring("property Foo")] HRESULT Foo([out, retval] BSTR* pVal);

[propput, helpstring("property Foo")] HRESULT Foo([in] BSTR newVal);

};

Для доступа к свойству Foo мастер сгенерирует два метода:

/////////////// в файле Mathem.h

STDMETHOD(get_Foo)(BSTR* pVal);

STDMETHOD(put_Foo)(BSTR newVal);

////////////// в файле Mathem.cpp

STDMETHODIMP CMathem::get_Foo(BSTR* pVal)

{

// TODO: Add your implementation code here

return S_OK;

}

STDMETHODIMP CMathem::put_Foo(BSTR newVal)

{

// TODO: Add your implementation code here

return S_OK;

}

Если мы собираемся хранить значение этого свойства в классе CMathem (а не получать его от господа бога или дьявола), то надо, очевидно, добавить в этот класс соответствующий компонент. Например, опишем в классе CMathem (файл Mathem.h) такой член-данное и инициализируем его в конструкторе:

BSTR m_bstrFoo; // добавлено

public:

CMathem()

{

m_bstrFoo=0; // добавлено

}

Реализация методов чтения и записи значения свойства Foo может быть выполнена следующим образом (файл Mathem.cpp):

STDMETHODIMP CMathem::get_Foo(BSTR* pVal)

{

*pVal=SysAllocString(m_bstrFoo);

return S_OK;

}

STDMETHODIMP CMathem::put_Foo(BSTR newVal)

{

SysFreeString(m_bstrFoo);

m_bstrFoo=SysAllocString(newVal);

return S_OK;

}

Обращаю ваше внимание на то, что работа со строками BSTR существенно отличается от работы с другими типами строк: для выделения и освобождения памяти надо использовать специальные функции выделения и освобождения памяти: SysAllocString() и SysFreeString() вместо привычных операций new и delete.

В клиентском приложении использование свойства (но только с применением интеллектуальных указателей на интерфейс) будет выглядеть так же, как и в Object Pascal, а именно:

pMathem->Foo=_T("Property testing");

wcout<<"Property Foo=="<<pMathem->Foo<<endl;

Как пишут писатели, внимательный читаттель обратит внимание на то, что метод get_Foo() извращает результат не посредством своего имени, а посредством параметра, в то время как вызов этого метода выглядит так, как будто это функция, возвращающая строку?! Чудеса, глюки или и то и другое вместе? Разбирайтесь.

Регистрация сервера в реестре Windows.

В версии MVS-2010 (как и в версиях 2005 и 2008) сервер автоматически регистрируется после его успешной сборки. Альтернативный способ регистрации сервера, как уже указывалось выше, состоит в подаче команды

Regsvr32 путь\имя_сервера

из командной строки. Например:

Regsvr32 C:\Temp\Lab4\DLLMathServer\Debug\DLLMathServer.dll

Разрегистрировать сервер можно с помощью команды

Regsvr32 /u путь\имя_сервера

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

Для тестирования сервера надо разработать клиентское приложение, которое может быть консольным приложением, приложением Win32, оконным приложением и др. Вот за него, с большим энтузиазмом, и возьмемся двумя руками.

Разработка и использование «обычных» библиотек DLL (CUI)

Есть моменты, когда все удается. Не ужасайтесь, это пройдет

Закон Мерфи

Цель работы – освоение технологии разработки и использования «обычных» библиотек DLL (Regular DLL using shared MFC DLL). В рамках этой работы мы построим обычную DLL-библиотеку, экспортирующую одну-единственную функцию. Далее надо разработать простое клиентское приложение, использующее эту библиотеку. Таким образом, мы получим аж два приложения – и все это за 2 час. с перекурами!

Задание. Рекомендуемая последовательность выполнения работы:

1. Ознакомиться с теоретической частью работы, для чего придется изучить раздел конспекта «Разработка и использование собственных DLL», особенно подраздел «Основы DLL».

2. Создать обычную (regular) библиотеку DLL, экспортирующую не класс, а просто одну или несколько функций.

3. Создать клиентское приложение, использующее разработанную библиотеку.

Наши рекомендации