Разработка динамических (DLL) библиотек. Разработка текста DLL-библиотеки.
Во-первых, этот код должен быть рассчитан на то, что он получает управление в одном из четырех случаев. О наступлении каждого из этих случаев операционная система извещает DLL-библиотеку путем передачи ей одного из четырех предопределенных значений – флагов. Значения этих флагов перечислены в файле winnt.h. Рассмотрим эти флаги и возможные действия при их поступлении в DLL-библиотеку.
- DLLPR0CESSATTACH-1 – передается операционной системой DLL-библиотеке при проецировании последней в адресное пространство процесса. Передача этого флага DLL-библиотеке производится всего один раз, обычно при загрузке приложения, использующего данную DLL-библиотеку. Если позже другой поток процесса попытается загрузить эту же библиотеку, то система попросту увеличит ее счетчик использования без посылки флага DLLPROCESSATTACH. Получив данный флаг, DLL-библиотека должна выполнить действия по созданию необходимой среды функционирования для своих функций. Например, обеспечить их кучей.
- DLL_THREAD_ATTACH=2 – передается операционной системой DLL-библиотеке при создании нового потока в процессе. Этим DLL-библиотеке предоставляется возможность нужным образом обработать факт создания нового потока. Следует иметь в виду, что этот процесс не является обратимым, то есть если DLL-библиотека загружается в процесс, когда в нем уже функционируют потоки, то ни одному из них не посылается флаг DLL_THREAD_ATTACH.
- # DLL_THREAD_DETACH=3 – передается операционной системой DLL-библиотеке при выгрузке потоком DLL-библиотеки.
- # DLL_PROCESS_DETACH=0 – передается операционной системой DLL-библиотеке при выгрузке DLL-библиотеки из адресного пространства процесса. Логично, что при этом требуется провести завершающие действия по освобождению всех ресурсов, которыми владеет DLL-библиотека. Обычно эти действия являются обратными по отношению к предпринятым при инициализации библиотеки (см. флаг DLLPROCESSATTACH).
Во-вторых, имя точки входа DLL-библиотеки может быть любым. Главное, чтобы при наличии кода инициализации это имя было указано в директиве END.
В-третьих, оформление кода инициализации в виде отдельной процедуры необязательно. Главное, выполнить два основных действия кода инициализации DLL-библиотеки (при его наличии):
- # вернуть единицу в регистре ЕАХ;
- # удалить из стека три параметра, которые передаются DLL-библиотеке при передаче описанных выше флагов: hlnstDLL – дескриптор DLL-библиотеки, назначенный ей системой при ее загрузке в адресное пространство процесса;
- vent – значение флага, передаваемого в DLL-библиотеку;
- f ImpLoad – параметр не равен 0, если библиотека загружена неявно (см. ниже), и равен 0 в обратном случае.
Структура полного варианта инициализационного кода выглядит так:
includeWindowConA.inc;"проверьте присутствие значений флагов в этом файле" DllMain ргос arg hlnstDLL:dword .event:dword,fImpLoad:dword cmp [event].DLL_PROCESS_ATTACH jne m выполняем действия для DLL_PROCESS_ATTACH cmp [event].DLL_THREAD_ATTACH jnem:выполняем действия для DLL_THREAD_ATTACH cmp [event]. DLL_THREAD_DETACH jnem выполняем действия для DLL_THREAD_DETACH cmp [event].DLL_PROCESS_DETACH jne m выполняем действия для DLL_PROCESS_DETACH m: moveax.l ret DllMainendp
Минимальный вариант может выглядеть так, как это сделано в нашем примере:
DllMain рrос arg hlnstDLL:dword .event:dword,fImpLoad:dword m: mov eax.l ret DllMainendp
Или так:
DllMain: m: moveax.l ret 12
Не забывайте, что директива arg приводит к тому, что в код, генерируемый транслятором, вставляются команды ENTERD и LEAVED (см. выше разделы "Реализация рекурсивных процедур" и "Реализация вложенных процедур"). Кроме этого, команда RET процедуры дополняется значением, равным сумме длин параметров, указанных в директиве ARG. Исполнение такой команды приводит к удалению из стека количества байт, равного этому сформированному значению.
Что касается кода функций (процедур), составляющих DLL-библиотеку, то для их написания используются обычные правила разработки программ. Описание данных также ничем не отличается от обычной программы ассемблера. Ведь в конечном итоге код и данные процедур DLL-библиотеки оказываются в адресном пространстве процесса наравне с его кодом и данными.
Последнее, что необходимо отметить, – все экземпляры данных и имена процедур, которые должны быть видны вне пределов DLL-библиотеки, объявляются общими с использованием одной из директив PUBLIC или PUBLICDLL.