The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Отложенная загрузка библиотек под Windows (gcc lib)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: gcc, lib,  (найти похожие документы)
From: Владислав Лазаренко <vlazarenko at miratech.biz> Newsgroups: email Date: Mon, 16 Nov 2004 14:31:37 +0000 (UTC) Subject: Отложенная загрузка библиотек под Windows Отложенная загрузка библиотек Владислав Лазаренко, 17 ноябрь 2004 Целостность программного продукта --------------------------------- Как вы знаете, многие программы зависят от каких-либо динамически подключаемых библиотек, которые содержат определенный код, используемый в программе (исполняемом файле). Таким образом, чтобы сохранить целостность программного продукта, на компьютере пользователя обязательно должны присутствовать не только исполняемые файлы, но и необходимые библиотеки. Как правило, такие зависимости проверяются на этапе установки, и никаких ошибок в последствии не возникает, но бывают и другие, более сложные ситуации. Например, заказчик поставил задачу написать программу, которая должна проверять наличие установленного СУБД клиента (в виде динамически подключаемых библиотек) и, если клиент установлен, выполнить определенные операции с СУБД, используя эту библиотеку. А что же произойдет, если какой-то из библиотек не окажется? Все очень просто - произойдет ошибка на этапе загрузки исполняемого файла операционной системой. В ОС Windows , например, будет показано неприветливое окно с надписью " Unable to locate DLL ". Самое обидно в этой ситуации то, что управление не будет передано программе, и вы никак не сможете эту ситуацию корректно обработать, хотя иногда это очень необходимо. Что такое отложенная загрузка библиотек и для чего она нужна ------------------------------------------------------------ Существует несколько решений описанной выше проблемы. Одно из них - запускать одну программу из скрипта или другой программы и проверять корректность её запуска и/или выполнения. Это выглядит не очень элегантно, к тому же в ОС Windows будет показан диалог, на который пользователь должен будет среагировать нажатием кнопки " OK ", а это не всегда приемлемо. Есть второе, более трудоемкое решение; оно заключается в том, чтобы не линковать программу с динамически подключаемыми библиотеками, а загружать их на этапе выполнения. Этого можно добиться с помощью функций загрузки библиотеки и поиска символов внутри неё. Для ОС Windows это функции LoadLibrary и GetProcAddress , в UNIX системах это функции dlopen и dlsym . Все очень просто, в начале выполнения программы пытаемся загрузить все необходимые функции из библиотек вручную, если это не удается, завершаем выполнение программы с определенным кодом ошибки. Это и называется отложенная загрузка библиотек. Microsoft идет навстречу программистам -------------------------------------- Разработчики Visual C ++ решили облегчить жизнь программистам, теперь, от версии 6.0, не нужно заниматься сложной и кропотливой работой, писать код для загрузки библиотек и обработки ошибок. Линкер предоставляет опцию / DelayLoad для отложенной загрузки библиотеки. Загрузка библиотеки будет автоматически происходить только перед первым вызовом функции из оной. Хочу заметить, что отложенная загрузка kernel 32. dll не поддерживается. Загрузка библиотеки происходит в " user space " с помощью функции, которая находится в библиотеке delayimp и называется helper функция. Если вы используете механизм отложенной загрузки, то должны линковать программу с этой библиотекой. Указание библиотек для отложенной загрузки ------------------------------------------ Вы можете указать, какие библиотеки должны загружаться по мере выполнения программы с помощью опции линкера / DelayLoad : DLLName . Ниже приведен пример отложенной загрузки user 32. dll : // cl t . cpp user 32. lib delayimp . lib / link / DELAYLOAD : user 32. dll # include < windows . h > // не комментируйте следующие две строки, чтобы убрать . libs из командной строки // #pragma comment (lib, "delayimp") // #pragma comment (lib, "user32") int main () { // user 32. dll будет загружена здесь MessageBox(0, "Hello", "Hello", MB_OK); return (0); } Явная выгрузка библиотеки ------------------------- Опция линкера / delay : unload позволяет вам явно выгрузить библиотеку. По умолчанию это делается автоматически тогда, когда вызовы из этой библиотеки более не используются, при этом адреса этих вызовов остаются в IAT ( import address table ). Однако если вы сделаете это вручную с помощью опции / delay : unload и функции __FUnloadDelayLoadedDLL2, то вспомогательная функция загрузки символов ( helper function ) сбрасывает значения в IAT . Пример: // линкуем с опциями / link / DELAYLOAD : MyDLL . dll / DELAY : UNLOAD #include <windows.h> #include <delayimp.h> #include "MyDll.h" #include <stdio.h> #pragma comment (lib, "delayimp") #pragma comment (lib, "MyDll") int main() { BOOL TestReturn; // MyDLL.DLL будет загружена тут fnMyDll (); // MyDLL . dll будет выгружена тут TestReturn = __FUnloadDelayLoadedDLL2("MyDll.dll"); if (TestReturn) ( void ) printf ("\ n библиотека была выгружена"); else ( void ) printf ("\ n библиотека не была выгружена"); return (0); } Имплементацию функции __ FUnloadDelayLoadedDLL 2 вы можете найти в файле Visual Studio -\ VC 7\ INCLUDE \ DELAYHLP . CPP . Загрузка всех символов из библиотеки ------------------------------------ Функция __ HrLoadAllImportsForDll , которая определена в файле delayhlp . cpp загружает все символы из указанной библиотеки. Использование этой функции позволяет обработать возможные ошибки в едином месте вашего кода, без отлавливания исключений на этапе вызова каждой функции загруженной библиотеки. Пример: if ( FAILED (__ HrLoadAllImportsForDll (" delay 1. dll "))) { ( void ) printf ("ошибка загрузки символов\ n "); exit(2); } Обработка ошибок ---------------- Как и везде, в загрузке тоже может произойти ошибка. Как её обработать, если вспомогательная функция загрузки вызывается анонимно? Очень просто, для этого существуют так называемые указатели на функции обработчики ( hooks ). Есть два таких указателя, это указатель на функцию обработки ошибок и на функцию, которая обрабатывает нотификации (оповещения о каком-либо действии). Указатель такого типа определяется так: typedef FARPROC ( WINAPI * PfnDliHook ) ( unsigned dliNotify , PDelayLoadInfo pdli ); Определение типа PDelayLoadInfo : typedef struct DelayLoadInfo { DWORD cb; // размер структуры PCImgDelayDescr pidd ; // что угодно здесь FARPROC * ppfn ; // указатель на загружаемую функцию LPCSTR szDll ; // имя библиотеки DelayLoadProc dlp ; // имя процедуры HMODULE hmodCur ; // hInstance загруженной библиотеки FARPROC pfnCur ; // функция-обработчик, которая будет вызвана DWORD dwLastError ; // ошибка (если нотификация об ошибке) } DelayLoadInfo, * PDelayLoadInfo; Оповещения ---------- Функция оповещения вызывается перед тем, как должно выполниться то или иное действие в функции загрузки. Параметром передается флаг предстоящей операции. Указатель определяется так (уже определен): ExternC PfnDliHook __ pfnDliNotifyHook 2; Флаги операций: 1) Проверка, загружена ли уже библиотека 2) Вызов функции LoadLibrary для обработки библиотеки 3) Вызов функции GetProcAddress для получения адреса процедуры 4) Завершение всех операций Ошибки ------ Указатель определяется так (уже определен): ExternC PfnDliHook __pfnDliFailureHook2; 1) Ошибка загрузки библиотеки в память 2) Ошибка поиска адреса процедуры в загруженной библиотеке Обратите внимание, что в конце имен определенных указателей стоят цифры 2, это только для Visual Studio версии 7.0, для версии же 6.0 двойки в имени отсутствуют. * Пример программы, в которой загружается библиотека mydll . dll и обрабатывается ошибка: // cl example.cpp /link /DELAYLOAD:mydll.dll #include <windows.h> #include <delayimp.h> #pragma comment (lib, "delayimp") #pragma comment (lib, "mydll") // если необходимую библиотеку/функцию не удалось найти, // корректно завершаем выполнение программы, возвращая код 1 static FARPROC WINAPI MyLibLoadFailure(unsigned notify, DelayLoadInfo *info) { exit(1); } int main() { __pfnDliFailureHook = NWLoadFailure; // установили свой обработчик ошибок // mydll . dll будет загружена здесь my _ foo (); return (0); } По материалам MSDN и собственного опыта. Автор: Владислав Лазаренко <vlazarenko at miratech.biz >. Все права защищены. Рецензенты : 1) Степанов Кирилл <kstepanov at miratech.biz>

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

 Добавить комментарий
Имя:
E-Mail:
Заголовок:
Текст:




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру