Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
РАБ_C++BUILDER.doc
Скачиваний:
100
Добавлен:
02.06.2015
Размер:
7.07 Mб
Скачать

Примеры статического и динамического связывания dll

Продолжим работу с DLL и напишем тестирующее приложение. Чтобы более гибко переключаться между отлаживаемой библиотекой и кодом теста, объединим с помощью Менеджера проекта модуль DLL и тестирующий проект в одну группу. Сначала рассмотрим реализацию статического связывания.

  1. Выполним команду Вид/Менеджер проекта. Откроется окно Менеджера проекта с одной вершиной MyDLL.dll. Развернем её (рис.10.5) и снова свернем.

Рис.10.5 – окно Менеджера проекта с загруженной DLL

Рис.10.6 – в окне Менеджера проекта появилась новая вершина

  1. В окне Менеджера проекта нажмем кнопку Новый и в окне Новые элементы на странице Новый выберем пиктограмму Приложение. Нажмем ОК. На экране появится пустая форма. Выполним команду Вид/Менеджер проекта и увидим, что в окне Менеджера проекта появилась вершина Project1.exe, соответствующая создаваемому тестовому приложению (рис.10.6).

  2. Выполним команду Файл/Сохранить проект как и сохраним модуль тестового приложения под именем UTestDLL, а проект – под именем PTestDLL.

Рис.10.7 – окно Менеджера проекта с загруженной DLL и тестом

  1. Введем команду Файл/Сохранить все и сохраним проект под именем TESTDLL. Снова выполним команду Вид/Менеджер проекта и в окне Менеджера проекта увидим загруженную DLL и вершину PTestDLL.exe, соответствующую создаваемому тестовому приложению (рис.10.7).

  2. Разместим на форме окно редактирования Edit1 и кнопку Button1 (рис.10.8).

а) б)

Рис.10.8 – тестовое приложение DLL: исходный текст в окне (а)

и результат кодировки (б)

В модуле приложения в обработчик щелчка на кнопке поместим оператор:

Edit1->Text = Code_Dec(Edit1->Text.c_str(),’A’);

Он берет текст, занесенный пользователем в окно редактирования Edit1, кодирует его с помощью функции Code_Dec и возвращает закодированную строку в Edit1.

  1. Включим в модуль приложения после директивы препроцессора #pragma hdrstop директиву, подключающую заголовочный файл библиотеки:

#include “UMyDLL.h”

Приведем заголовочный файл модуля UTestDLL.h:

//---------------------------------------------------------------------------

#ifndef UTestDLLH

#define UTestDLLH

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

//---------------------------------------------------------------------------

class TForm1 : public TForm

{

__published: // IDE-managed Components

TEdit *Edit1;

TButton *Button1;

void __fastcall Button1Click(Tobject *Sender);

private: // User declarations

public: // User declarations

__fastcall TForm1(TComponent* Owner);

};

//---------------------------------------------------------------------------

extern PACKAGE TForm1 *Form1;

//---------------------------------------------------------------------------

#endif

и файл реализации модуля UTestDLL.cpp:

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include “UMyDLL.h”

#include “UTestDLL.h”

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource “*.dfm”

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(Tcomponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(Tobject *Sender)

{

Edit1->Text = Code_Dec(Edit1->Text.c_str(),’A’);

}

//---------------------------------------------------------------------------

  1. Осталось подключить к тестирующему приложению файл .lib, обеспечивающий статическое связывание библиотеки. Для этого сначала нужно активизировать приложение в окне Менеджера проекта, выделив вершину проекта PTestDLL.exe и нажав на кнопку Активизировать (рис.10.9).

Рис.10.9 – подготовка к активизированию приложения

  1. Введём команду Проект/Добавить к проекту… . Во всплывшем диалоговом окне выберем шаблон файлов «Файл библиотеки (*.lib)» и выберем файл MyDLL.lib. Файл библиотеки окажется включенным в тестирующее приложение (рис.10.10). Это обеспечит при запуске приложения статическое связывание библиотеки.

  2. Теперь можно сохранить проект, откомпилировать и выполнить его. Результаты работы приложения показаны на рис.10.8.

Рис.10.10 – файл библиотеки включен в тестирующее приложение

  1. Перейдем к рассмотрению варианта динамического связывания. В окне Менеджера проекта нажмем кнопку Новый и в окне Новые элементы на странице Новый выберем пиктограмму Приложение. Нажмем ОК. На экране появится пустая форма.

  2. Выполним команду Файл/Сохранить проект как и сохраним (в том же каталоге, где находится DLL) модуль под именем UTestDLL2, а проект – под именем PTestDLL2. С помощью окна Менеджера проекта убедимся, что второе тестирующее приложение добавлено (рис.10.11).

Рис.10.11 - окно Менеджера проекта с загруженной DLL,

первым тестом PTestDLL.exe и вторым тестом PTestDLL2.exe

Рис.10.12 – тестовое приложение динамического связывания DLL

  1. Разместим на форме окно редактирования Edit1 и три кнопки Button1,2,3 (рис.10.12). Кнопка Загрузить (имя BLoad) будет обеспечивать загрузку DLL, кнопка Выгрузить (имя BFree) будет выгружать библиотеку из памяти, а кнопка Кодировать/Декодировать (имя Button1) аналогична той, которая была в первом приложении.

  2. В заголовочном файле второго приложения в описание класса формы нужно внести объявления (см. ниже).

//---------------------------------------------------------------------------

#ifndef UTestDLL2H

#define UTestDLL2H

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

//---------------------------------------------------------------------------

class TForm2 : public TForm

{

__published: // IDE-managed Components

TEdit *Edit1;

TButton *Button1;

TButton *BLoad;

TButton *BFree;

void __fastcall BLoadClick(TObject *Sender);

void __fastcall BFreeClick(TObject *Sender);

void __fastcall Button1Click(TObject *Sender);

private: // User declarations

// Объявление указателя на DLL

HINSTANCE dllInstance;

// Объявление указателя на функцию

typedef char* (__import FType(char *, char));

FType * C_D;

public: // User declarations

__fastcall TForm2(TComponent* Owner);

};

//---------------------------------------------------------------------------

extern PACKAGE TForm2 *Form2;

//---------------------------------------------------------------------------

#endif

//---------------------------------------------------------------------------

Переменная dllInstance будет содержать указатель на загруженный модуль DLL. Вводимый тип FType соответствует типу функции Code_Dec, которая будет вызвана из библиотеки. А переменная C_D будет содержать указатель на эту функцию.

  1. Приведем файл реализации модуля формы второго приложения:

#include <vcl.h>

#pragma hdrstop

#include "UTestDLL2.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm2 *Form2;

//---------------------------------------------------------------------------

__fastcall TForm2::TForm2(TComponent* Owner)

: TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TForm2::BLoadClick(TObject *Sender)

{

// Загрузка DLL

dllInstance = LoadLibrary("MyDLL.dll");

if(dllInstance)

// получение указателя на функцию

C_D = (FType *)GetProcAddress(dllInstance, "_Code_Dec");

else ShowMessage(«Не удалось загрузить 'MyDLL.dll'»);

}

//---------------------------------------------------------------------------

void __fastcall TForm2::BFreeClick(TObject *Sender)

{

// выгрузка DLL

FreeLibrary(dllInstance);

C_D = NULL;

}

//---------------------------------------------------------------------------

void __fastcall TForm2::Button1Click(TObject *Sender)

{

if (C_D)

Edit1->Text = C_D(Edit1->Text.c_str(),'A');

else ShowMessage(

" Функция 'Code_Dec' из 'MyDLL.dll' недоступна");

}

//---------------------------------------------------------------------------

Обработчик BLoadClick загружает библиотеку функцией LoadLibrary. Если загрузить библиотеку не удалось, то значение dllInstance окажется равным NULL. В этом случае пользователю выдается сообщение «Не удалось загрузить 'MyDLL.dll'». А если загрузка прошла успешно, то методом GetProcAddress в переменную C_D заносится указатель на импортируемую функцию.

Обработчик Button1Click обеспечивает вызов функции с помощью указателя C_D. А если указатель равен NULL (например, в библиотеке не оказалось требуемой функции, что в нашем случае невозможно, или перед выполнением Button1Click не была загружена библиотека, что в нашем случае возможно), то пользователю выдается соответствующее сообщение об ошибке.

Обработчик BFreeClick выгружает функцией FreeLibrary из памяти модуль DLL и обнуляет указатель C_D.

  1. Выполним данное приложение и убедимся, что все работает нормально (рис.10.12).

  2. Проведите эксперимент, размещая исполняемый файл тестового приложения и файл библиотеки в различных каталогах.