Явная загрузка DLL
В любой момент поток может спроецировать DLL на адресное пространство процесca, вызвав одну из двух функций:
HINSTANCE LoadLibrary{PCTSTR pszDLLPathName);
HINSTANCE LoadLibraryEx( PCTSTR pszDLLPathName, HANDLE hFile, DWORD dwFlags);
Обе функции ищут образ DLL-файла (в каталогах, список которых приведен в предыдущей главе) и пытаются спроецировать его на адресное пространство вызывающего процесса. Значение типа HINSTANCE, возвращаемое этими функциями, сообщает адрес виртуальной памяти, но которому спроецирован образ файла. Если спроецировать DLL на адресное пространство процесса не удалось, функции возвращают NULL Дополнительную информацию об ошибке можно получить вызовом GetLastError.
Очевидно, Вы обратили внимание на два дополнительных параметра функции LoadLibraryEx, hFile и dwFlags. Первый зарезервирован для использования в будущих версиях и должен быть NULL Bo втором можно передать либо 0, либо комбинацию флагов DONT_RESOLVE_DLL_REFERENCES, LOAD_LIBRARY_AS_DATAFILE и LOAD_WITH_ALTERED_SEARCH_PATH, о которых мы сейчас и поговорим.
СОЗДАНИЕ DLL
1 ) Заголовочный файл с экспортируемыми прототипами структурами и идентификаторами (символьными именами) 2) Исходные файлы С/С++ в которых реализованы экспортируемые функции и определены переменные 3) Компилятор создает OBJ-файл из каждого исходного файла С/С++ 4) Компоновщик собирает DLL из OBJ модулей 5) Если DLL экспортирует хотя бы одну переменную или функцию компоновщик создает и LIB-файл {при явном связывании этот файл не используется) | СОЗДАНИЕ ЕХЕ
6) Заголовочный файл с импортируемыми прототипами, структурами и идентификаторами 7) Исходные файлы С/С++ в которых нет ссылок на импортируемые функции и переменные 8) Компилятор создает OBJ файл из каждого исходного файла С/С++ 9) Компоновщик собирает ЕХЕ-модуль из OBJ-модулей (LIB файл DLL не нужен, так как нет прямых ссылок на экспортируемые идентификаторы, раздел импорта в ЕХЕ-модуле отсутствует) |
Рис. 20-1. Так DLL создается и явно связывается с приложением
DONT_RESOLVE_DLL_REFERENCES
Этот флаг указывает системе спроецировать DLL на адресное пространство вызывающего процесса. Проецируя DLL, система обычно вызывает из нее специальную функцию DllMain (о ней — чуть позже) и с ее помощью инициализирует библиотеку. Так вот, данный флаг заставляет систему проецировать DLL, не обращаясь к DllMain.
Кроме того, DLL может импортировать функции из других DLL. При загрузке библиотеки система проверяет, использует ли она другие DLL; если да, то загружает и их. При установке флага DONT_RESOLVE_DLL_REFERENCES дополнительные DLL автоматически не загружаются.
LOAD_LIBRARY_AS_DATAFILE
Этот флаг очень похож на предыдущий. DLL проецируется на адресное пространство процесса так, будто это файл данных. При этом система не тратит дополнительное время на подготовку к выполнению какого-либо кода из данного файла Например, когда DLL проецируется на адресное пространство, система считывает информацию из DLL-файла и на ее основе определяет, какие атрибуты защиты страниц следует присвоить разным частям файла. Если флаг LOAD_LIBRARY_AS_DATAFILE не указан, атрибуты защиты устанавливаются такими, чтобы код из данного файла можно было выполнять.
Этот флаг может понадобиться по нескольким причинам. Во-первых, его стоит указать, если DLL содержит только ресурсы и никаких функций. Тогда DLL проецируется на адресное пространство процесса, после чего при вызове функций, загружающих ресурсы, можно использовать значение HINSTANCE, возвращенное функцией LoadLibraryEx. Во-вторых, он пригодится, если Вам нужны ресурсы, содержащиеся в каком-нибудь ЕХЕ-файле. Обычно загрузка такого файла приводит к запуску нового процесса, но этого не произойдет, если его загрузить вызовом LoadLibraryEx в адресное пространство Вашего процесса. Получив значение HINSTANCE для спроецированного ЕХЕ-файла, Вы фактически получаете доступ к его ресурсам. Так как в ЕХЕ-файле нет DllMain, при вызове LoadLibraryEx для загрузки ЕХЕ-файла нужно указать флаг LOAD_LIBRARY_AS_DATAFILE.
LOAD_WITH_ALTERED_SEARCH_PATH
Этот флаг изменяет алгоритм, используемый LoadLibraryEx при поиске DLL-файла. Обычно поиск осуществляется так, как я рассказывал в главе 19 Однако, если данный флаг установлен, функция ищет файл, просматривая каталоги в таком порядке