7 Структурное программирование 2012
.pdf31
Рисунок 7.4 – Окно подключения к программе lib-файла
Пример программа статического импорта созданных ресурсов DLL: //---------------------------------------------------------------------------
#include <iostream.h> // Подключение статических модулей
#include <conio.h> #pragma hdrstop #pragma argsused
extern "C" __declspec(dllimport) int Max(int X, int Y); // импорт функции Max extern "C" __declspec(dllimport) int Min(int X, int Y); // импорт функции Min int main(int argc, char* argv[]) // Главная функция -------------------------
{cout << "Maximum : " << Max(10,-5) << endl;
cout << "Minimum : " << Min(3,100); getch();
return 0; }//---------------------------------------------------------------------------
Cсуществует три способа динамического импорта функций из DLL:
1)по имени в программе;
2)по имени в DLL-библиотеке;
3)по индексу.
Два последних способа подразумевают использование DEF-файла.
На момент компиляции программы DLL-библиотека, которую она подключает, может еще и не существовать. Что означает независимую разработку приложений и DLL.
Подключить DLL-библиотеку в программе позволяет функция:
HINSTANCE LoadLibrary(LPCTSTR “имя dll-файла”);
При успешном завершении функция возвращает дескриптор загруженной DLLбиблиотеки, а иначе — код ошибки в диапазоне от 0 до 32.
Пример загрузки динамической библиотеки
HINSTANCE LibHandle;
if((LibHandle = LoadLibrary("MathLib.dll")) < (HINSTANCE)32)
{printf("Невозможно загрузить DLL\n");
return 1; }//--------------------
Если в памяти нет загруженной DLL-библиотеки с заданным именем, файл DLLбиблиотеки считывается с диска и загружается в оперативную память. Счетчик привязок динамической библиотеки увеличивается на 1 при каждом вызове LoadLibrary.
После завершения работы с библиотекой она освобождается функцией
BOOL FreeLibrary(дескриптор DLL). LoadLibrary и FreeLibrary можно вызывать для одного и того же модуля несколько раз.
32
После загрузки динамической библиотеки можно использовать функцию GetProcAddress для получения адресов экспортируемых функций. GetProcAddress возвращает указатель на точку входа в экспортируемую подпрограмму.
FARPROC GetProcAddress(HMODULE hModule, LPCSTR IpProcName);
где hModule — дескриптор загруженного DLL-модуля;
IpProcName — имя или целочисленный индекс подпрограммы, экспортируемой DLL. Если функция импортируется по имени, то в параметре IpProcName передается
указатель на строку, содержащую имя подпрограммы. Если экспорт по номеру, то в двух младших байтах параметра IpProcName передается ее индекс, а старшие два байта должны быть равны 0.
Если нет функции с указанным именем IpProcName, тогда GetProcAddress возвратит NULL. При попытке получить адрес подпрограммы не по имени, а по индексу, значение функции GetProcAddress будет не равно NULL, даже при отсутствии функции с указанным индексом. С помощью GetProcAddress не возможно получить только информацию о параметрах экспортируемой функции. При динамическом импорте очень удобными оказываются typedef объявление типа указателя на функцию. Пример указателя типа функций Min и Мах:
typedef int(*MinMax)(int, int) ;
Для хранения адреса функции DLL в программе объявляется переменная указанного типа. Например:
MinMax Min, Max;
Если теперь присвоить переменной Min результат вызова GetProcAddress, то ее можно будет использовать в дальнейшем для вызова функции динамической библиотеки.
Min = MinMax(GetProcAddress(LibHandle, "_Min"));
Знак подчеркивания перед именем Min необходим, так как компилятор C++Builder добавляет его ко всем именам, объявленным как extern "С".
Пример |
|
|
|
#include <windows.h> |
|
|
|
#include <iostream.h> |
|
|
|
#include <conio.h> |
|
|
|
#pragma hdrstop |
|
|
|
#pragma argsused |
|
|
|
typedef int(*MinMax)(int, int); // определение |
типа указателя на функцию |
||
MinMax Minn, Maxx; |
// определение |
указателей на функции |
|
int main(int argc, char* argv[]) |
|
|
|
{ HINSTANCE LibHandle; |
// Определение дескриптора DLL |
||
if((LibHandle = LoadLibrary("ProjectDLL.dll")) |
< (HINSTANCE)32) // Загрузка DLL |
||
{ cout << "Невозможно загрузить DLL"; |
// |
Сообщение об ошибке загрузки |
|
getch(); |
|
// |
приостановка закрытия окна |
return -1; |
|
// |
Возврат кода ошибки |
} //if |
|
|
|
Minn=MinMax(GetProcAddress(LibHandle,"_Min")); |
// импорт функции Min |
||
Maxx=MinMax(GetProcAddress(LibHandle,"_Max")); |
// импорт функции Max |
||
cout << "Maximum : " << Maxx(10,-5) << endl;// |
определение максимума двух чисел |
||
cout << "Minimum : " << Minn(3,100); |
// |
определение минимума |
|
FreeLibrary(LibHandle); |
|
// |
отключение DLL |
getch(); |
|
// |
приостановка закрытия окна |
return 0; |
|
// |
код успешного завершения |
}//--------------------------------------------------------------------------- |
|
|
|
Динамический импорт следующие достоинства:
1)более эффективное использование ресурсов оперативной памяти, так как DLL загружается и выгружается из памяти по мере надобности;
2)программе предоставляется полный контроль над подключением DLLбиблиотек, благодаря чему динамический импорт применим в тех случаях, когда подключаемые процедуры и функции могут отсутствовать в DLL-библиотеке и требуется особая обработка ошибок доступа к библиотеке и ее процедурам и функциям.