Существует несколько способов подключения DLL библиотеки — явный и неявный. Для неявного подключения библиотеки к проекту, необходимо иметь заголовочный файл библиотеки, файл импорта «.lib» и «.dll» файл. Для явного же подключения можно иметь всего лишь «.dll» файл, но при этом дополнительно нужно знать имена функций и переменных. Какой же смысл по-разному подключать библиотеки? Об этом читайте далее…

При неявном подключении, линкеру передается именно библиотека импорта («.lib» файл). Этот файл содержит в себе некие ссылки на функции, которые находятся внутри динамической библиотеки «.dll». Использование данного способа подключения влечет за собой загрузку используемых программой динамических библиотек в память. При этом загруженные библиотеки остаются в памяти до завершения работы программы.

При явном же подключении библиотеки, можно обойтись наличием всего лишь одного файла динамической библиотеки «.dll». Этот способ более изящен по отношению к использованию системных ресурсов, так как во власти программиста остается возможность загрузки и выгрузки библиотеки на любом этапе работы программы.

Существует еще один способ загрузки и использования DLL — отложенная загрузка (реализована только в продуктах «Visual C++», начиная с версии «6.0»). Суть ее в том, чтобы автоматически подключить библиотеку к проекту только тогда, когда произойдет хоть один вызов библиотечной функции (метода и т.п.) из программы. Если в процессе работы ни одна библиотечная функция не используется, то и библиотека вообще не загрузится в программу. Данный способ очень удобный и выгодный, в случае если программа использует большое количество библиотек. Кроме того, имеется возможность даже после загрузки библиотеки программным путём выгрузить её. К минусам данного способа можно отнести отсутствие кроссплатформенности  данного решения (насколько мне известно, данный способ отсутствует на платформах *nix).

Перейдем к практике…

 

В этой статье мы с Вами рассмотрим все три способа использования DLL на примере. Я решил создать решение (solution) в среде программирования «Visual Studio 2005″ которое, в свою очередь, состоит из 4 проектов (projects):

  • Проект «DynamicLibrary» – это проект для создания динамической библиотеки.
  • Проект «ImplicitLinking» – это пример неявного подключения динамической библиотеки к проекту.
  • Проект «ExplicitLinking» – это пример явного подключения динамической библиотеки к проекту.
  • Проект «DelayLoadLinking» – пример отложенной загрузки библиотеки.

 

Все с перечисленных проектов генерируют выходные файлы в общую директорию («debug» или «release»). Это сделано для удобства, так как каждый из проектов будет использовать одну и ту же библиотеку («.lib» и «.dll» файлы);

Рассмотрим детальнее каждый из проектов.

 

Проект «DynamicLibrary». Создание библиотеки функций. Создание библиотеки было рассмотрено в статье «Как создать динамическую библиотеку?», поэтому рассмотрение данного шага в этой статье считаю избыточным.

 

Проект «ImplicitLinking». Пример неявного подключения. Проект минималистичен, так как содержит всего один файл. Как было сказано ранее, для данного способа подключения библиотеки достаточно иметь заголовочный файл библиотеки, «.lib» файл и «.dll» файл.
В коде, сначала подключаем заголовочный файл:

 

#include "DynamicLibrary.h"

 

Библиотеку импорта подключаем, используя директиву прекомпилятора:

 

#pragma comment (lib, "DynamicLibrary.lib")

 

Этого вполне достаточно для дальнейшего использования библиотеки в программе. Содержимое результирующего файла «ImplicitLinking.cpp»:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "DynamicLibrary.h"
#include <iostream>
 
using namespace std;
 
// Linking the library
#pragma comment (lib, "DynamicLibrary.lib")
 
int main(int argc, char* argv[])
{
cout<<"Implicit linkage example program!"<<endl;
 
cout<<"Calculated value: "<<ADD(100.567, 194.6)<<endl;
 
cout<<"Press any key for exit!"<<endl;
 
getchar();
 
return 0;
}

 

Перейдем к рассмотрению примера программы по явному подключению динамической библиотеки.

 

Проект «ExplicitLinking». Пример явного подключения динамической библиотеки. Данный метод подключения несколько сложнее неявного метода. Для начала необходимо загрузить саму динамическую библиотеку с помощью функции LoadLibrary(…):

 

HMODULE h = LoadLibrary(L"DynamicLibrary.dll");

 

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

 

double (*fun)(double, double);

 

Следующим этапом является получение адреса функции с последующим присваиванием его нашему указателю:

 

(FARPROC &) fun = GetProcAddress(h, "ADD");

 

После проделанных операций можно смело приступать к использованию имени указателя на функцию (т. е. работать с ним как с именем обычной функции):

 

cout<<"Calculated value: "<<fun(100.567, 194.6)<<endl;

 

Если мы больше не нуждаемся в загруженной библиотеке ее можно выгрузить:

 

FreeLibrary(h);

 

Содержимое результирующего файла « ExplicitLinking.cpp»:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <windows.h>
 
using namespace std;
 
// Pointer on the function
double (*fun)(double, double);
 
int main(int argc, char* argv[])
{
cout<<"Explicit linkage example program!"<<endl;
 
// Loading the dll library
HMODULE h = LoadLibrary(L"DynamicLibrary.dll");
 
// Assigning the address of function from the dll to the pointer
(FARPROC &) fun = GetProcAddress(h, "ADD");
 
// Call imported from the dll function and show the result
cout<<"Calculated value: "<<fun(100.567, 194.6)<<endl;
 
cout<<"Press any key to free the library!"<<endl;
 
getchar();
 
// Free the library from system memory
FreeLibrary(h);
 
cout<<"Press any key for exit!"<<endl;
 
getchar();
 
return 0;
}

 

Читателю может показаться, что динамическое подключение библиотеки совсем не сложное дело и вообще-то это действительно так, но не во всех случаях. Когда речь идет о десятке или же сотне функций или переменных, то реализация динамической линковки становится трудоемкой задачей (если сравнивать с неявным подключением динамической библиотеки). Существует ещё одна модификация того, как можно динамически подключать DLL но, честно говоря, мне было лень описывать этот способ. Кто заинтересован в том, как динамически подключать библиотеку с использованием так называемых «.def» файлов могут об этом почитать тут.

 

Проект «DelayedLinkageExample». Отложенная загрузка библиотеки. Мы успешно разобрались с явным и неявным подключением динамической библиотеки. Рассмотрим последний (известный мне) способ использования библиотеки — отложенную загрузку.

Этот способ заключается в использовании дополнительной библиотеки «Delayimp.lib». В коде это выглядит следующим образом:

 

1
2
3
#include <Delayimp.h>
...
#pragma comment(lib, "Delayimp.lib")

 

Кроме этого, нужно указать линкеру, какую из библиотек мы желаем запускать отложено. Это можно сделать, зайдя в настройки проекта «Properties->Configuration Properties->Linker->Input->Delay Loaded DLLs».

В остальном, данный способ напоминает подключение динамической библиотеки методом неявного подключения. Полный текст примера программы представлен ниже:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "DynamicLibrary.h"
 
#include <iostream>
#include <windows.h>
#include <Delayimp.h>
 
using namespace std;
 
#pragma comment(lib, "DynamicLibrary.lib")
#pragma comment(lib, "Delayimp.lib")
 
// This method doesn't works after VS6 version
//#pragma comment(linker, "/DELAYLOAD:DynamicLibrary.dll")
 
int main(int argc, char* argv[])
{
cout<<"Delayed linkage example program!"<<endl;
 
// Call imported from the dll library function and show the result
cout<<"Calculated value: "<<ADD(100.567, 194.6)<<endl;
 
cout<<"Press any key for exit!"<<endl;
 
getchar();
 
return 0;
}

 

Мы видим закомментированные строки кода:

 

// This method doesn't works after VS6 version
//#pragma comment(linker, "/DELAYLOAD:DynamicLibrary.dll")

 

Дело в том, что в версии «Visual Studio 6.0″ можно было использовать директиву «#pragma comment(linker, «/DELAYLOAD:…dll»)» для указания линкеру библиотеки с отложенной загрузкой, но в дальнейших версиях VS поддержка данной функции из кода была отключена.

Кроме всего написанного, существует возможность выгрузить библиотеку отложенной линковки до завершения программы с помощью функции __FUnloadDelayLoadedDLL2(«…») но для этого нужно указать дополнительные настройки в свойствах проекта. Для этого необходимо перейти настройки проекта «Linker->Advanced->DelayLoaded Dll’s» и выбрать опцию «Support Unload».

 

Загрузка

Скачать исходный код проекта

 

Ссылки

  1. Тут показан пример работы с отложенной загрузкой DLL.
  2. Тут сказано, что библиотека отложенной загрузки не может быть указана через прагму.
  3. Тут показано, как можно динамически линковать библиотеку используя .def файлы.
  4. Тут объяснено для чего нужно писать extern «C» в объявлениях функций библиотеки (для того, чтобы линкер не искажал имена).