Поделиться через


Библиотеки DLL расширения

Обновлен: Ноябрь 2007

Библиотека DLL расширения MFC — это библиотека DLL, реализующая обычно классы многократного использования, производные от существующих классов библиотеки Microsoft Foundation Class.

Функциональные возможности и требования для библиотеки DLL расширения MFC:

  • Исполняемый клиентский файл должен быть приложением MFC, скомпилированным с _AFXDLL.

  • Библиотека DLL расширения также может использоваться регулярной библиотекой DLL, которая динамически скомпонована с MFC.

  • Библиотеки DLL расширения должны быть скомпилированы с _AFXEXT. Это также задает _AFXDLL и обеспечивает извлечение специфических объявлений из файлов заголовков MFC. Кроме того, это гарантирует определение AFX_EXT_CLASS в качестве __declspec(dllexport) при построении библиотеки DLL, которая необходима при использовании этого макроса для объявления классов в библиотеке DLL расширения.

  • Библиотеки DLL расширения не инициализируют класс, производный от CWinApp, но полагаются на клиентское приложение (или библиотеку DLL) для предоставления этого объекта.

  • Библиотеки DLL расширения, однако, предоставляют функцию DllMain и выполняют в ней любую необходимую инициализацию.

Построение библиотек DLL расширения выполняется с помощью библиотеки динамической компоновки версии MFC (известной также как общая версия MFC). Только исполняемые файлы MFC (приложения или обычные библиотеки DLL), которые создаются с общей версией MFC, могут использовать библиотеку DLL расширения. Клиентское приложение и библиотека DLL расширения должны использовать одну и ту же версию MFCx0.dll. С помощью библиотеки DLL расширения можно создать новые пользовательские классы на основе MFC и затем применять эту расширенную версию MFC в приложениях, которые вызывают библиотеку DLL.

Библиотеки DLL расширения могут также использоваться для передачи объектов, производных от MFC, между приложением и библиотекой DLL. Функции-члены, ассоциируемые с передаваемым объектом, находятся в модуле, в котором объект был создан. Поскольку эти функции соответствующим образом экспортируются при использовании общедоступной версии библиотеки DLL MFC, возможна свободная передача указателей на объекты MFC или указателей на объекты, производные от MFC, между приложением и библиотеками приложений, которые его загружают.

Библиотека DLL расширения MFC использует общедоступную версию MFC точно так, как приложение использует общедоступную версию библиотеки DLL MFC, учитывая следующее:

  • Отсутствие CWinApp-производного объекта. Возможность работы с CWinApp-производным объектом клиентского приложения. Это означает, что клиентское приложение обладает конвейером обработки основных сообщений, циклом бездействия и т. д.

  • Вызов AfxInitExtensionModule для своей функции DllMain. Возвращаемое значение этой функции должно быть проверено. Если AfxInitExtensionModule возвращает нулевое значение, необходимо возвратить 0 из функции DllMain.

  • Создание объекта CDynLinkLibrary в процессе инициализации, если библиотека DLL расширения будет экспортировать объекты CRuntimeClass или ресурсы в приложение.

До версии 4.0 of MFC этот тип библиотеки DLL назывался AFXDLL. AFXDLL ссылается на символ предварительной обработки _AFXDLL, который определяется при построении библиотеки DLL.

Импортируемые библиотеки для общедоступной версии MFC называются в соответствии с соглашением, описанным в Соглашениях об именовании библиотек DLL MFC. Visual C++ предоставляет предварительно построенные версии MFC библиотек DLL, а также библиотеки DLL, не относящиеся к MFC, которые можно использовать и распространять с приложением. Эти библиотеки перечислены в файле Redist.txt, который устанавливается в папке Program Files\Microsoft Visual Studio.

При экспорте с использованием DEF-файла в начале и в конце заголовка файла следует поместить следующий код:

#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA

Эти четыре строки гарантируют правильную компиляцию кода для библиотеки DLL расширения. Пропуск этих четырех строк может привесит к некорректной компиляции или компоновке библиотеки DLL.

При необходимости передать указатель на объект MFC или MFC-производный объект в библиотеку DLL MFC или из нее, библиотека DLL должна быть библиотекой DLL расширения. Функции-члены, ассоциируемые с передаваемым объектом, находятся в модуле, в котором объект был создан. Поскольку эти функции соответствующим образом экспортируются при использовании общедоступной версии библиотеки DLL MFC, возможна свободная передача указателей на объекты MFC или указателей на объекты, производные от MFC, между приложением и библиотеками приложений, которые его загружают.

В силу искажения и экспорта имен C++, список экспорта из библиотеки DLL расширения может быть различным у отладочных и распространяемых версий одной и той же библиотеки DLL и библиотек DLL для различных платформ. В распространяемой версии MFCx0.dll имеется около 2 000 экспортированных точек входа; в отладочной версии MFCx0D.dll — около 3 000 экспортированных точек входа.

Управление памятью

MFCx0.dll и все библиотеки DLL расширения, загруженные в адресное пространство клиентского приложения, используют одни и те же распределение памяти, загрузку ресурсов и другие глобальные состояния MFC, как если бы они находились в одном приложении. Это является важным, поскольку библиотеки DLL, не относящиеся к MFC, и регулярные библиотеки DLL ведут себя совершенно противоположно; выделение памяти для каждой библиотеки DLL осуществляется из собственного пула памяти.

При выделении памяти библиотекой DLL расширения происходит свободное распределение памяти между любыми объектами в приложении. Кроме того, если приложение, динамически скомпонованное с MFC, дает сбой, защита операционной системы поддерживает целостность любого другого приложения MFC, использующего библиотеку DLL.

Аналогично другие глобальные состояния MFC, такие как текущий исполняемый файл для загрузки ресурсов, также совместно используются клиентским приложением, всеми библиотеками DLL расширения MFC и самой MFCx0.dll.

Общий доступ к ресурсам и классам

Экспорт ресурсов осуществляется по списку ресурсов. Каждое приложение содержит однонаправленный список объектов CDynLinkLibrary. При поиске ресурса большинство стандартных реализаций MFC, загружающих ресурсы, сначала производят поиск в текущем модуле ресурсов (AfxGetResourceHandle), и если ресурс не найден проходят по списку объектов CDynLinkLibrary, пытаясь загрузить запрошенный ресурс.

Проход по списку имеет тот недостаток, что он немного медленнее и требует управления уровнями идентификатора ресурса. Преимуществом является то, что клиентское приложение, связанное с несколькими библиотеками DLL расширения, может использовать любой предоставленный библиотекой DLL ресурс без указания дескриптора экземпляра библиотеки DLL. AfxFindResourceHandle представляет собой API, используемый для прохода по списку ресурсов в поиске заданного совпадения. В эту функцию передаются имя и тип ресурса, будет возвращен дескриптор ресурса, где он был найден в первый раз (или значение "NULL").

Функции AfxGetResourceHandle и AfxSetResourceHandle используются для сохранения старого дескриптора и задания нового, если необходимо только загрузить ресурсы из определенного места, а не проходить по всему списку. Перед возвратом к клиентскому приложению убедитесь в том, что старый дескриптор ресурсов восстановлен. Пример использования такого подхода для явной загрузки меню, см. Testdll2 .cpp в примере MFC DLLHUSK.

Процесс динамического создания объектов MFC, заданных MFC именем точно такой же. Механизм десериализации объекта MFC требует регистрации всех объектов CRuntimeClass, чтобы сделать возможным восстановление путем динамического создания объектов C++ требуемого типа на основе того, что было сохранено ранее.

В случае с примером MFC DLLHUSK список выглядит примерно так:

head ->   DLLHUSK.EXE   - or -   DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL           TESTDLL2.DLL
               |                      |
          TESTDLL1.DLL           TESTDLL1.DLL
               |                      |
           MFCOxxD.DLL                |
               |                      |
           MFCDxxD.DLL                |
               |                      |
            MFCxxD.DLL            MFCxx.DLL

где xx — номер версии; например, 42 представляет версию 4.2.

MFCxx.dll обычно стоит последней в списке ресурсов и классов. MFCxx.dll включает в себя все стандартные ресурсы MFC, в том числе командные строки для всех стандартных идентификаторов команд. Ее расположение в конце списка позволяет библиотекам DLL и самим клиентским приложениям не содержать свою собственную копию стандартных ресурсов MFC, а вместо этого, полагаться на общедоступные ресурсы в MFCxx.dll.

Слияние имен ресурсов и классов всех библиотек DLL в пространстве имен клиентского приложения имеет тот недостаток, что необходимо соблюдать осторожность при подборе идентификаторов и имен.

Пример DLLHUSK управляет пространством имен общедоступного ресурса с помощью нескольких файлов заголовков.

Если для библиотеки DLL расширения MFC требуется сохранить дополнительные данные для каждого приложения, можно создать новый, производный от CDynLinkLibrary класс в DllMain. При запуске текущий список приложения объектов CDynLinkLibrary может проверяться библиотекой DLL для поиска объекта для конкретной библиотеки DLL расширения.

Выполняемые задачи

Дополнительные сведения

См. также

Основные понятия

Библиотеки DLL