Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Связывание по символьным именам против связывания по порядковым номерам
Связывание по порядковым номерам в Win16 было эффективнее и предлагалось по умолчанию. В Win32 связывание по символьным именам усовершенствовано, и теперь Microsoft рекомендует использовать именно его. Однако в DLL-версии библиотеки MFC применяется связывание по порядковым номерам. Дело в том, что типичная программа на базе MFC подключается к сотням функций этой библиотеки, и при связывании по порядковым номерам ЕХЕ-файл получается компактнее, поскольку отпадает необходимость хранить длинные символьные имена импортируемых элементов. Если Вы создаете DLL со связыванием по порядковым номерам, определите в DEF-файле проекта номера, которые не слишком часто используются в Win32. Если Вы экспортируете функции С++, то должны указывать в DEF-файле их расширенные имена (или объявить функции как “extern С”). Вот краткий фрагмент одного из DEF-файлов MFC-библиотеки: ?ReadList@CRecentFileList@@UAEXXZ @ 5458 NONAME ?ReadNameDictFromStream@CPropertySection@@QAEHPAUIStream@@@Z @ 5459 NONAME ?ReadObject@CArchive@@QAEPAVCObject@@PBUCRuntimeClass@@@Z @ 5460 NONAME ?ReadString@CArchive@@QAEHAAVCString@@@Z @ 5461 NONAME ?ReadString@CArchive@@QAEPADPADI@Z @ 5462 NONAME ?ReadString@CInternetFile@@UAEHAAVCString@@@Z @ 5463 NONAME ?ReadString@CInternetFile@@UAEPADPADI@Z @ 5464 NONAME
Числа после символов @ – это и есть порядковые номера. Ну что, Вы no-прежнему хотите использовать этот метод? Точка входа в DLL: функция DllMain По умолчанию компоновщик предполагает, что точкой входа в вашу DLL является функция _DllMaintCRTStartup(). Windows, загружая DLL, вызывает эту функцию, а та сначала вызывает конструкторы глобальных объектов, потом — глобальную функцию DllMain(), которую Вы, естественно, должны были написать. DIIMain() вызывается не только при подключении DLL к процессу, но и при отключении от него, а также в ряде других случаев. Взгляните на заготовку функции DllMain(): HINSTANCE g_hInstance; extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) { TRACE0("EX22A.DLL Initializing!\n"); // здесь реализуйте инициализацию } else if (dwReason == DLL_PROCESS_DETACH) { TRACE0("EX22A.DLL Terminating!\n"); // здесь реализуйте очистку } return 1; // ok }
Если Вы не пишете функцию DllMain() для своей DLL, вместо нее подставляется заглушка из стандартной библиотеки выполнения. Функция DllMain вызывается также при запуске и завершении отдельных потоков, что определяется параметром dwReason. Впрочем, эта тема исчерпывающе изложена в книге Джеффри Рихтера.
Описатели экземпляров и загрузка ресурсов
Каждая DLL в процессе идентифицируется уникальным 32-разрядным значением HINSTANCE. Сам процесс тоже имеет описатель HINSTANCE. Все эти описатели экземпляров действительны только в рамках конкретного процесса и представляют собой начальный виртуальный адрес DLL- или ЕХЕ-модуля. В Win32 значения описателей HINSTANCE и HMODULE совпадают и эти описатели равнозначны. Описатель экземпляра процесса почти всегда равен 0х400000, а у DLL с базовым адресом по умолчанию — 0х10000000. Если ваша программа использует несколько DLL, то у них будут разные значения HINSTANCE — либо потому, что в DLL указаны разные базовые адреса (определяется на этапе разработки), либо потому, что загрузчик скопировал и переместил код DLL. Описатели экземпляров особенно важны при загрузке ресурсов. В частности, параметр HINSTANCE необходим Win32-функции FindResource(). В ЕХЕ- и DLL-модулях могут быть свои ресурсы. Если нужен ресурс из DLL, указывают описатель экземпляра DLL, а если из ЕХЕ – описатель экземпляра ЕХЕ. Как же получить описатель экземпляра? Вы уже видели, что описатель экземпляра DLL передается как параметр в функцию DllMain(). Если Вы хотите выяснить описатель ЕХЕ-модуля, вызовите Win32-функцию GetModuleHandle(NULL). Если же Вам нужен описатель DLL, вызовите GetModuleHandle() с именем DLL в качестве параметра. Позднее мы рассмотрим еще один метод загрузки ресурсов, реализованный в MFC-библиотеке, основанный на просмотре модулей в определенной последовательности.
Порядок поиска DLL клиентской программой
Если Вы компонуете программу явным образом, с использованием LoadLibrary(), то можете указывать полное имя DLL (с определением пути). Если же полный путь не указан или при неявной компоновке Windows будет искать вашу DLL в следующем порядке: 1 В каталоге, содержащем данный ЕХЕ-файл. 2 В текущем каталоге процесса. 3 В системном каталоге Windows. 4 В каталоге Windows. 5 В каталогах, прописанных в переменной окружения PATH.
Здесь есть одна ловушка, в которую можно запросто угодить. Вы создаете DLL как отдельный проект, затем копируете DLL-файл в системный каталог Windows и, наконец, загружаете DLL в клиентскую программу. До сих пор все было прекрасно. Но вот Вы обновляете DLL, забываете скопировать ее в системный каталог и при следующем запуске клиентской программы загружается старая версия DLL. Что тут сказать — будьте внимательны! Отладка DLL Как, при необходимости, трассировать код библиотечных функций и, например, просмотреть значения переменных, если библиотека не может исполняться как самостоятельное приложение? Загрузите в ИС проект библиотеки RegDLL и попробуйте запустить отладку с помощью F5, предварительно установив контрольную точку в какой-либо библиотечной функции (это можно сделать и потом или использовать другие команды и приемы отладки). При первом таком запуске библиотеки на отладку вам будет показано окно с сообщением об ошибке: невозможно запустить библиотеку. Выход на самом деле есть: надо для библиотеки указать вызывающий процесс и тогда отладчик запустит его и позволит отлаживать библиотеку. Последовательность действий такова. 1. Во вкладке Solution Explorer выберите проект библиотеки: в нашем случае это RegDLL. 2. В меню View выполите команду Property Pages. 3. В окне RegDLL Property Pages в выпадающем списке Configuration выберите Active(Debug) В папке Configuration Properties выберите категорию Debugging. 4. В списке Debugger to launch list выберите Local Windows Debugger. 5. Откройте выпадающий список Command, выберите в нем команду Browse и с ее помощью укажите расположение и имя вызывающего процесса, в нашем случае это Lab1.exe. 6. Закончите работу нажатием Применить и ОК.
Заметьте, что после выполнения этих настроек библиотеки ее надо вновь построить и вновь скопировать файл RegDLL.dll в папку с исполняемым файлом Lab1.exe. |
||
Последнее изменение этой страницы: 2018-04-12; просмотров: 394. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |