
- •1.Назначение динамически подключаемых библиотек
- •2. Dll и адресное пространство процесса
- •2.Создание dll
- •3.Использование dll с библиотекой импорта (неявное связывание)
- •4. Использование dll без библиотеки импорта (явное связывание)
- •5. Создание dll модуля
- •6. Порядок выполнения работы
- •7. Контрольные вопросы
2. Dll и адресное пространство процесса
Зачастую создать DLL проще, чем приложение, потому что она является лишь набором автономных функций, пригодных для использования любой программой, причем в DLL обычно нет кода, предназначенного для обработки циклов выборки сообщений или создания окон DLL представляет собой набор модулей исходного кода, в каждом из которых содержится определенное число функций, вызываемых приложением (исполняемым файлом) или другими DLL. Файлы с исходным кодом компилируются и компонуются так же, как и при создании ЕХЕ-файла. Но, создавая DLL, необходимо указывать компоновщику ключ /DLL. Тогда компоновщик записывает в конечный файл информацию, по которой загрузчик операционной системы определяет, что данный файл — DLL, а не приложение.
Чтобы приложение (или другая DLL) могло вызывать функции, содержащиеся в DLL, образ ее файла нужно сначала спроецировать на адресное пространство вызывающего процесса. Это достигается либо за счет неявного связывания при загрузке, либо за счет явного — в период выполнения.
Как только DLL спроецирована на адресное пространство вызывающего процесса, ее функции доступны всем потокам этого процесса. Фактически библиотеки при этом теряют почти всю индивидуальность: для потоков код и данные DLL — просто дополнительные код и данные, оказавшиеся в адресном пространстве процесса. Когда поток вызывает из DLL какую-то функцию, та считывает свои параметры из стека потока и размещает в этом стеке собственные локальные переменные. Кроме того, любые созданные кодом DLL объекты принадлежат вызывающему потоку или процессу — DLL ничем не владеет,
Например, если DLL-функция вызывает VirtualAlloc, резервируется регион в адресном пространстве того процесса, которому принадлежит поток, обратившийся к DLL функции. Если DLL будет выгружена из адресного пространства процесса, зарезервированный регион не освободится, так как система не фиксирует того, что регион зарезервирован DLL-функцисй. Считается, что он принадлежит процессу и поэтому освободится, только если поток этого процесса вызовет VirtualFree или завершится сам процесс.
Библиотеки DLL очень полезны, если вы программируете под Windows. В этих библиотеках обычно хранят часто используемые подпрограммы. Далее рассказывается, как создать простую DLL и показано, как вызвать функции, содержащиеся в ней. Примеры рассчитаны на использование Microsoft Visual C++ 6.0, но нетрудно перевести их на любой диалект C++.
2.Создание dll
Ничего особенного здесь нет. Как обычно, вы просто пишите функции, как в обычной программе. Если вы используете MSVC, создайте новый проект и укажите, что вы создаете Win32 Dynamic-Link Library. После компиляции вы получите DLL, библиотеку импорта (.lib) и библиотеку экспорта (.exp). Далее показан примерный код DLL:
Заголовочный файл (DLLTEST.H)
#ifndef _DLLTEST_H_ #define _DLLTEST_H_ #include <iostream.h> #include <stdio.h> #include <windows.h> extern "C" __declspec(dllexport) void NumberList(); extern "C" __declspec(dllexport) void LetterList(); #endif |
Код библиотеки (DLLTEST.CPP)
#include "dlltest.h" #define MAXMODULE 50 char module[MAXMODULE]; extern "C" __declspec(dllexport) void NumberList() { GetModuleFileName(NULL, (LPTSTR)module, MAXMODULE); cout << "\n\nThis function was called from " << module << endl << endl; cout << "NumberList(): "; for(int i=0; i<10; i++) { cout << i << " "; } cout << endl << endl; } extern "C" __declspec(dllexport) void LetterList() { GetModuleFileName(NULL, (LPTSTR)module, MAXMODULE); cout << "\n\nThis function was called from " << module << endl << endl; cout << "LetterList(): "; for(int i=0; i<26; i++) { cout << char(97 + i) << " "; } cout << endl << endl; } |
Как видите, ничего особенного в коде нет. Приложение, используемое для примера - консольное, так что здесь просто запрограммированы две функции, выводящие текст. Строка extern "C" __declspec(dllexport) означает, что функция будет видна вне DLL (т.е. ее можно вызывать из нашей программы). После компиляции мы получим библиотеку. Теперь посмотрим, как ее можно использовать.