Статическое и динамическое связывание DLL с приложением

 

Библиотеки DLL могут связываться с приложением двумя путями: статическим связыванием или динамическим связыванием.

При статическом связывании DLL загружается сразу, как только начинает выполняться приложение, которое будет ее использовать. Это наиболее простой способ использования DLL. Вызов функций в приложении при этом почти не отличается от вызова любых других функций. Здесь время загрузки увеличивается и нельзя выполнять приложение, если нет соответствующего файла DLL. Кроме того, без DLL приложение не может выполняться и в сокращенном, также рабочем варианте. Недостатком статического связывания является и то, что DLL занимает память все время, в течение которого выполняется приложение, независимо от того, вызываются ли в данном сеансе работы с приложением какие-то функции библиотеки, или нет.

Статическое связывание подразумевает, что для DLL создан специальный файл описаний импортируемых функций (import library file). Этот файл имеет расширение .lib и то же имя, что и соответствующая DLL, и должен быть связан с приложением на этапе компиляции.

При динамическом связывании DLL загружается только в тот момент, когда необходимо выполнить какую-то хранящуюся в ней функцию. Затем DLL можно выгрузить из памяти. Но при более эффективном использовании памяти вызов функций DLL существенно усложняется, и время вызова увеличивается.

Для вызова библиотечной функции надо сначала загрузить библиотеку функцией LoadLibraryAPI Windows. Затем с помощью функции GetProcAddress надо получить указатель на нужную функцию библиотеки. Только после этого можно выполнять функцию. А затем с помощью функции FreeLibrary надо выгрузить библиотеку из памяти.

Предположим, создана библиотека mydll.dll, содержащая некоторую функцию char* MyFunction(char*). Тогда для загрузки DLL надо выполнить оператор вида:

 

//загрузка DLL

HINSTANSE dllInstanse =LoadLibrary(“mydll.dll”);

 

Получить указатель на импортируемую функцию можно следующим кодом:

 

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

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

FType * MyFunc;

MyFunc = (FType*)GetProcAddress(dllInstanse, “_MyFunction”);

 

Объявление typedef вводит пользовательский тип (тип-функция) с произвольным именем FType. Введенный тип используется для задания типа указателя на функцию MyFunc. Для получения значения этого указателя используется функция API Windows GetProcAddress. Она принимает в качестве параметров указатель на загруженный модуль DLL и имя функции, а возвращает указатель на функцию. Этот указатель приводится к типу указателя на используемую функцию библиотеки.

Вызов функции осуществляется с помощью указателя на неё:

 

//вызов функции

char* S = MyFunc(“Привет!”);

 

Когда работа с DLL завершена, её можно выгрузить из памяти оператором вида:

 

//выгрузка DLL

FreeLibrary(dllInstanse);

 

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