TN033: Версия библиотеки DLL MFC
Эта заметка описываются способы использования библиотек динамической компоновки MFCxx.DLL и MFCxxD.DLL (где x - номер версии MFC) совместно используемые с приложениями MFC и библиотеки DLL расширения.Дополнительные сведения об обычных библиотеках DLL см. в разделе Использование MFC как часть библиотеки DLL.
Эта заметка охватывает технический 3 аспекта библиотеки DLL.Последние 2 для опытных пользователей:
Как построении библиотеки DLL расширения MFC
Как построении приложения MFC, которое использует версию DLL MFC
В качестве библиотек динамической компоновки MFC на общие
Если нужно знать построения, то библиотеки DLL с помощью MFC, который можно использовать с приложениями, не являющихся mfc (это называется обычными DLL) см. в разделе Техническая примечание 11.
Общие сведения о поддержке MFCxx.DLL: Терминология и файлов
Regular DLL: Используется обычная библиотека DLL для построения изолированного библиотеки DLL с помощью некоторых классов MFC.Интерфейсы через границу App/DLL интерфейсы «c», а клиентское приложение не должно быть приложением MFC.
Это версия, поддерживаемая поддержки DLL в MFC 1.0.Это описывается в Техническая примечание 11 и расширенной MFC образце DLLScreenCap Основных понятий.
![]() |
---|
Начиная с версии Visual C++ 4.0 термин USRDLL устарел и была заменена обычная библиотека DLL, статически скомпонована с MFC.Можно также выполнить построение обычной библиотеки DLL, динамически скомпонована с MFC. |
MFC 3,0 (и выше) поддерживает обычные библиотеки DLL со всеми новых функциональных возможностей, включая классы OLE и базы данных.
AFXDLL: Это также называется общая версия библиотек MFC.Это новая поддержка библиотек DLL, добавленная в MFC 2.0.Сама библиотека MFC в нескольких библиотек DLL (описаны ниже) и клиентское приложение или библиотеки DLL, динамически связанные библиотеки DLL которых он требуется.Интерфейсы через границу application/DLL интерфейсы класса C++/MFC.Клиентское приложение ДОЛЖНО быть приложением MFC.Это действие поддерживает те же функции MFC 3,0 (исключение: ЮНИКОД не поддерживается для классов базы данных).
![]() |
---|
Начиная с версии Visual C++ 4.0, этот вид библиотек DLL называется «библиотека DLL расширения.» |
Эта заметка будет использовать MFCxx.DLL для обращения ко всему набору библиотек DLL MFC, который включает:
Отладка. (В сочетании MFCSxxD.LIB) и MFCxxD.DLL (статическое).
Выпуск: (MFCxx.DLL и объединенный) MFCSxx.LIB (статическое).
Юникод отладка. (Объединенный) MFCxxUD.DLL и MFCSxxD.LIB (статическое).
Выпуск Юникода. (Объединенный) MFCxxU.DLL и MFCSxxU.LIB (статическое).
![]() |
---|
Библиотеки MFCSxx [U] [D] .LIB используются совместно с dll-библиотекой MFC для совместного использования.Эти библиотеки содержат код, который требуется связать с приложением или статической библиотеки DLL. |
Связи приложения в соответствующий библиотеки импорта:
Отладка. MFCxxD.LIB
Выпуск: MFCxx.LIB
Юникод отладка. MFCxxUD.LIB
Выпуск Юникода. MFCxxU.LIB
«Библиотека DLL расширения MFC» библиотеки DLL, созданное в MFCxx.DLL (или других общих MFC DLL).Здесь архитектура компонентов пинает MFC.Если необходимо создать производный класс от класса MFC, полезный или построения других MFC-как набор средств, можно установить ее в библиотеке DLL., Что библиотека DLL использует MFCxx.DLL обычно, в клиентское приложение.Это позволяет многократно используемые классы конечного объекта, многократно используемые базовые классы и повторно используемых классов представления или документа.
Преимущества и недостатки
Почему следует использовать общедоступную версию MFC?
Использование общую библиотеку может привести к появлению небольших приложениях (минимальное приложение, которое использует большую часть библиотеки MFC, чем 10K).
Общая версия MFC поддерживает библиотеки DLL расширения MFC и обычные библиотеки DLL.
Построение приложения, которое использует общие библиотеки MFC выполняется быстрее, чем построение статически связанное приложение MFC, поскольку сам не должны быть связаны MFC.Это особенно справедливо в построениях отладка, когда компоновщик должен сжимать данные отладки — путем связывания с библиотекой DLL, которая уже содержит данные отладки, отладочных сведений для сжатия в приложении.
Почему следует использовать общедоступную версию MFC:
- Поставлять приложений, использующих общую библиотеку необходимо грузите библиотека MFCxx.DLL и других () с программой.MFCxx.DLL свободно распространяемый пакет как можно больше библиотеки DLL, но по-прежнему должны установить библиотеку DLL в программе установки.Кроме того, необходимо предоставить MSVCRTxx.DLL, содержащего библиотеку C среды выполнения, которая используется как программой непосредственно, так и MFC DLL.
Как создать библиотеку DLL расширения MFC
Библиотека DLL расширения MFC DLL, содержащий классы и функции, написанные для оформления функциональность классов MFC.Библиотека DLL расширения MFC использует общие библиотеки DLL MFC точно таким же образом приложение использует их и несколько дополнительных факторов:
Процесс построения похож на построение приложения, которое использует общие библиотеки MFC с небольшим количеством дополнительные параметры компилятора и компоновщика.
Библиотека DLL расширения MFC не имеет CWinApp- производный класс.
Библиотека DLL расширения MFC должен предоставить специальное DllMain.Предоставляет AppWizard функция DllMain, которые можно изменять.
Библиотека DLL расширения MFC обычно является предоставление процедуру инициализации для создания CDynLinkLibrary если библиотека DLL расширения следует экспортировать CRuntimeClass es или ресурсы в приложение.Производный класс CDynLinkLibrary может использоваться, если данные для каждого приложения должны поддерживаться библиотеки DLL расширения.
Это более подробно вопросы описано ниже.Также необходимо ссылаться в образце расширенной MFC Основных понятий DLLHUSK поскольку он иллюстрирует:
Построение приложения, использующие общие библиотеки.(DLLHUSK.EXE приложение MFC, которая динамически скомпонована в библиотеки MFC, а также другими DLL).
Построение библиотеки DLL расширения MFC.(Обратите внимание, как _AFXEXT особые флаги, которые используются при построении библиотеки DLL расширения)
2 Примера библиотеки DLL расширения MFC.Он указывает, что базовая структура библиотеки DLL расширения MFC с ограниченными экспортами (TESTDLL1) и отображает экспортировать весь интерфейс класса (TESTDLL2).
И клиентское приложение и все библиотеки DLL расширения должны использовать одну и ту же версию MFCxx.DLL.Вы должны соответствовать соглашению библиотеки DLL MFC и обеспечить и отладки и версии розницы (/release) библиотеки DLL расширения.Это позволяет программы клиента построения и отладки и розничные версии их приложений и связывает их с соответствующим debug или розничная версию всех библиотек DLL.
![]() |
---|
Поскольку проблемы mangling и экспорта имени C++, список покупок экспортных из библиотеки DLL расширения могут различаться от отладки и розничными версий одного и того же библиотеки DLL и библиотека DLL для разных платформ.MFCxx.DLL retail содержит около 2000 экспортированные точки входа; отладка MFCxxD.DLL содержит около 3000 экспортированные точки входа. |
Быстрая примечание об управлении памятью
Раздел под названием «управлением памятью» в конце этой технической заметки, описывается реализация MFCxx.DLL с общей версией MFC.Сведения необходимо знать для реализации просто библиотека DLL расширения описаны здесь.
MFCxx.DLL и все расширения DLL, загружаемые в адресное пространство клиентского приложения будут использоваться один и тот же распределитель памяти, загрузку ресурсов и другие глобальные состояния MFC «», как если бы они находились в одном приложении.Это важно, поскольку библиотеки DLL, не относящихся к mfc и обычные библиотеки DLL, статически связываются с MFC, что линия и обратное имеют каждое DLL, выбирая из своего собственного пула памяти.
Если библиотека DLL расширения выделяет память, эта память может свободно перемешать с любым другим приложение-выделенным объектом.Кроме того, если приложение, использующее общие библиотеки MFC разбивает, защита операционной системы будет поддерживать целостность любого другого общего доступа к приложениям MFC DLL.
Аналогично другие глобальные состояния MFC «», как текущий исполняемый файл, чтобы загрузить ресурсы из также совместно самим клиентским приложением и всеми библиотеками DLL расширения MFC, а также MFCxx.DLL.
Построение библиотеки DLL расширения
Можно использовать AppWizard для создания проекта библиотеки DLL расширения MFC, и оно автоматически создает соответствующие параметры компилятора и компоновщика.Он был также создает функцию DllMain, которые можно изменять.
При преобразовании существующий проект в библиотеке DLL расширения MFC, начните с стандартным правилам для построения приложения с помощью общедоступную версию MFC, а затем выполните следующие действия.
Добавьте /D_AFXEXT к флагам компилятора.В диалоговом окне свойства проекта выберите узел C/C++.Затем выберите категорию препроцессора.Добавьте _AFXEXT к полю макросов определение, отделяя каждый из элементов отделяются друг от друга точкой с запятой.
Удалите параметр компилятора /Gy.В диалоговом окне свойства проекта выберите узел C/C++.Затем выберите категорию создания кода.Убедитесь, что параметру «разрешить» не включает компоновку на уровне функций.Это сделает его более удобным экспортирование классов, потому что компоновщик не удаляет неиспользуемая функции.Если используется исходном проекте построение обычной библиотеки DLL, статически связанное с MFC, измените параметр компилятора /MT[d] к /MD[d].
Построение библиотеки экспорта с параметром /DLL СВЯЗЫВАНИЕ.Это будет установлено при создании нового целевого объекта, учитывая библиотеки динамической компоновки Win32, таких как тип целевого объекта.
Изменить файлы заголовков
Назначение библиотеки DLL расширения обычно экспортировать некоторая общую функциональность к одному или нескольким приложениям, которые могут использовать эту функциональность.Это кипит вниз до глобального экспортировать классы и функции, которые доступны для клиентских приложений.
Для этого необходимо убедиться, что каждый из функции-члены помечается как импортировать или экспортировать как необходимо.Это требует специальных объявлений. __declspec(dllexport) и __declspec(dllimport).Когда классы используются клиентскими приложениями, нужных быть объявлены как __declspec(dllimport).Если библиотека DLL строится само по себе расширения, они должны быть объявлены как __declspec(dllexport).Кроме того, необходимо экспортировать функции фактически, благодаря чему программы клиента должны быть привязаны к ним во время загрузки.
Чтобы экспортировать для всего класса, используйте AFX_EXT_CLASS в определении класса.Этот макрос определяется платформой как __declspec(dllexport) при _AFXDLL и _AFXEXT указаны, но определен как __declspec(dllimport) при _AFXEXT не указано._AFXEXT, как описано выше, указано только при построении библиотеки DLL расширения.Примеры.
class AFX_EXT_CLASS CExampleExport : public CObject
{ ... class definition ... };
Частичный экспорт класса
Иногда может потребоваться экспортировать только отдельные обязательные члены класса.Например, при экспортировании класса, производного от CDialog, возможно, потребуется экспортировать только конструктора и вызов DoModal.Можно экспортировать эти члены с помощью def-файл библиотеки DLL, но также можно использовать AFX_EXT_CLASS в основном так же, как и в отдельных элементах необходимо экспортировать.
Примеры.
class CExampleDialog : public CDialog
{
public:
AFX_EXT_CLASS CExampleDialog();
AFX_EXT_CLASS int DoModal();
// rest of class definition
.
.
.
};
При этом можно выполнять в дополнительную проблему, так как вы больше не экспортировать все члены класса.Проблема, макросов MFC.Несколько вспомогательных макросов MFC объявляют или определяют члены данных.Поэтому этим элементам данных также требуется экспортированным из библиотеки DLL.
Например, при построении библиотеки расширения макрос DECLARE_DYNAMIC определяется следующим образом:
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
Линия, которая инициирует «статическое AFX_DATA» объявляет статический объект внутри класса.Чтобы экспортировать этот класс правильно и получить доступ к сведениям во время выполнения из клиента EXE, необходимо экспортировать этот статический объект.Поскольку статический объект объявляется вместе с модификатором AFX_DATA, необходимо определить AFX_DATA в качестве __declspec(dllexport) при построении библиотеки DLL, а также определить в качестве __declspec(dllimport) при построении исполняемого клиентского файла.
Как отмечалось выше, AFX_EXT_CLASS уже определено таким образом.Необходимо просто нужно re-определить AFX_DATA чтобы быть таким же, как AFX_EXT_CLASS вокруг вашего определения класса.
Примеры.
#undef AFX_DATA
#define AFX_DATA AFX_EXT_CLASS
class CExampleView : public CView
{
DECLARE_DYNAMIC()
// ... class definition ...
};
#undef AFX_DATA
#define AFX_DATA
MFC всегда использует символ AFX_DATA на элементах данных он определяет в пределах его макросов, поэтому этот метод будет работать для всех таких сценариев.Например, он будет работать для DECLARE_MESSAGE_MAP.
![]() |
---|
При экспортировании всего класса, а не отдельно выбранных членов, статические члены данных экспортируются автоматически. |
Можно использовать один и тот же метод автоматически, чтобы экспортировать оператор извлечения CArchive для классов, которые используют макросы DECLARE_SERIAL и IMPLEMENT_SERIAL.Экспортировать оператор архива, отыскивать вилку объявления классов (расположенные в. Файл h) следующим кодом:
#undef AFX_API
#define AFX_API AFX_EXT_CLASS
<your class declarations here>
#undef AFX_API
#define AFX_API
Ограничения директивы _AFXEXT
Можно использовать символ препроцессора AFXEXT _для библиотеки DLL расширения, если отсутствует несколько уровней библиотек DLL расширения.Если существующие библиотеки расширения вызывают методы или являются производными от классов, находящихся в других библиотеках расширения, которые, в свою очередь, являются производными от классов MFC, то в таком случае необходимо использовать особую директиву препроцессора, чтобы избежать неоднозначности.
Проблема заключается в том, что в Win32 требуется явно объявлять все данные как __declspec(dllexport), если они должны экспортироваться из данной DLL, и как __declspec(dllimport), если они должны импортироваться из другой DLL.Когда объявляется директива _AFXEXT, заголовочные классы MFC обеспечивают корректность объявления директивы AFX_EXT_CLASS.
Если имеется несколько слоев, один символ как AFX_EXT_CLASS не достаточно, поскольку библиотека DLL расширения, может экспортировать новые классы, а также импортировать другие классы из другой библиотеки DLL расширения.Для решения этой проблемы, используется специальный символ препроцессора, который указывает на то, что построении библиотеки DLL для использования самой библиотеке DLL.Например, представьте 2 библиотеки DLL расширения, A.DLL и B.DLL.Они каждый экспорт некоторые классы в A.H и B.H соответственно.B.DLL использует классы из A.DLL.Их заголовочные файлы выглядят примерно следующим образом:
/* A.H */
#ifdef A_IMPL
#define CLASS_DECL_A __declspec(dllexport)
#else
#define CLASS_DECL_A __declspec(dllimport)
#endif
class CLASS_DECL_A CExampleA : public CObject
{ ... class definition ... };
/* B.H */
#ifdef B_IMPL
#define CLASS_DECL_B __declspec(dllexport)
#else
#define CLASS_DECL_B __declspec(dllimport)
#endif
class CLASS_DECL_B CExampleB : public CExampleA
{ ... class definition .. };
При построении A.DLL, оно построено с /D A_IMPL и B.DLL, когда оно построено с /D B_IMPL.С помощью отдельных символов для каждого библиотеки DLL, CExampleB экспортированно и импортировано CExampleA при построении B.DLL.Экспортированно при построении A.DLL и импортировано CExampleA при использовании B.DLL (или другой клиентом).
Этот тип наслаивать нельзя сделать при использовании встроенных AFX_EXT_CLASS и символов препроцессора _AFXEXT.Метод, описанный выше решает эту проблему способом не в отличие от самого механизм MFC использует его при построении библиотеки DLL расширения OLE, базы данных и сети.
Частичный экспорт класса
Кроме того, необходимо позаботиться особый уход, если не экспортировать всего класса.Необходимо убедиться, что элементы необходимых данных, созданные помощью макроса MFC экспортированы правильно.Это делается с re-определяя AFX_DATA к макросу требований конкретного классов.Так следует поступать всегда, когда класс экспортируется частично.
Примеры.
// A.H
#ifdef A_IMPL
#define CLASS_DECL_A _declspec(dllexport)
#else
#define CLASS_DECL_A _declspec(dllimport)
#endif
#undef AFX_DATA
#define AFX_DATA CLASS_DECL_A
class CExampleA : public CObject
{
DECLARE_DYNAMIC()
CLASS_DECL_A int SomeFunction();
//class definition
.
.
.
};
#undef AFX_DATA
#define AFX_DATA
DllMain
Следующее точный код необходимо поместить в основном файле источника для библиотеки DLL расширения.Он должен находиться после стандарт включает.Обратите внимание, что при использовании AppWizard для создания начальных файлов для библиотеки DLL расширения, он предоставляет DllMain.
#include "afxdllx.h"
static AFX_EXTENSION_MODULE extensionDLL;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(
extensionDLL, hInstance))
return 0;
// TODO: perform other initialization tasks here
}
else if (dwReason == DLL_PROCESS_DETACH)
{
// Extension DLL per-process termination
AfxTermExtensionModule(extensionDLL);
// TODO: perform other cleanup tasks here
}
return 1; // ok
}
Вызов AfxInitExtensionModule перехватывает среда выполнения-классы модулей (структуры CRuntimeClass ), а также его фабрики объектов (объекты COleObjectFactory ) для дальнейшего использования, когда объект CDynLinkLibrary будет создан.Вызов (необязательно) в AfxTermExtensionModule позволяет очистка библиотеки DLL расширения MFC, когда каждый процесс, наконец, удаляется (который происходит, когда процесс или оставить если библиотека DLL выгружаются в результате вызова FreeLibrary ) из библиотеки DLL расширения.Поскольку большинство расширения DLL, динамически не загружаются (обычно они связаны через них библиотеки импорта), вызов AfxTermExtensionModule обычно не требуется.
Если приложение загружает и освобождает расширения DLL, динамически, необходимо вызвать AfxTermExtensionModule, как показано выше.Также убедитесь в том, AfxLoadLibrary и использовать AfxFreeLibrary (вместо функции Win32 LoadLibrary и FreeLibrary), если приложение использует несколько потоков или если она динамически загружает библиотеку DLL расширения.Использование AfxLoadLibrary и гарантирует, что AfxFreeLibrary запуска и завершения работы кода, который выполняется при загрузке и выгружаются библиотеки DLL расширения не может привести к повреждению глобального состояния MFC.
Файл заголовка AFXDLLX.H содержит специальные определения структур, используемых в библиотеке DLL расширения, например определение AFX_EXTENSION_MODULE и CDynLinkLibrary.
Глобальное extensionDLL должен быть объявлен как показано ниже.В отличие от шестнадцатиразрядную версию MFC, можно выделить память и вызов функции MFC в течение этого времени с момента MFCxx.DLL полностью инициализирован к моменту в DllMain вызывается.
Общий доступ к ресурсам и классам
Простой библиотеки DLL расширения MFC требуется экспортировать только несколько функций с низкой пропускной способностью клиентскому приложению и ничего более.Несколько библиотек DLL интерфейса пользователя может потребоваться экспортировать ресурсы, активно и классы C++ клиентскому приложению.
Экспорт ресурсов осуществляется по списку ресурсов.В каждом приложении однонаправленного списка объектов CDynLinkLibrary.При поиске ресурса большинство стандартных реализаций MFC, загружающих ресурсы сначала ищет в текущем модуле ресурсов (AfxGetResourceHandle) и если найдена проверка список объектов CDynLinkLibrary при попытке загрузить запрошенный ресурс.
Динамическое создание объектов C++ заданное имя класса с++ аналогичным образом.Механизм десериализации объекта MFC необходимо иметь все зарегистрированные объекты CRuntimeClass таким образом, чтобы он мог восстановить динамически создать объект C++ требуемого типа на основе что было сохранено ранее.
Если требуется клиентское приложение использовать классы в библиотеке DLL, то расширения, которые DECLARE_SERIAL, то необходимо будет экспортировать классы для быть видимо клиентскому приложению.Это также можно сделать, CDynLinkLibrary прохода по списку.
В случае примеры MFC Основных понятий расширенной DLLHUSK список выглядит как нечто:
head -> DLLHUSK.EXE - or - DLLHUSK.EXE
| |
TESTDLL2.DLL TESTDLL2.DLL
| |
TESTDLL1.DLL TESTDLL1.DLL
| |
| |
MFC90D.DLL MFC90.DLL
MFCxx.DLL обычно является последним в списке ресурсов и класса.MFCxx.DLL включает все стандартные ресурсы MFC, в том числе командные строки для всех стандартных идентификаторов команд.Установить его на кабеле списка позволяет библиотеки DLL и клиентское приложение не иметь собственную копию стандартных ресурсов MFC, но полагаться на общих ресурсах в MFCxx.DLL.
Слияние ресурсы и имена классов всех библиотек DLL в пространство имен клиентского приложения имеет недостаток заключается в том, что необходимо соблюдать осторожность, какие идентификаторы или имена выборе.Конечно, можно отключить эту функцию, чтобы не экспортировать или ресурсов или объект CDynLinkLibrary клиентскому приложению.Пример DLLHUSK управляет пространством имен общедоступного ресурса с помощью нескольких файлов заголовков.См. раздел Техническая примечание 35 дополнительные советы по об использовании файлов общего ресурса.
Инициализация библиотек DLL
Как упоминалось выше, нужно создать объект CDynLinkLibrary чтобы экспортировать свои ресурсы и классы клиентскому приложению.Необходимо будет предоставлять экспортированную точку входа для инициализации библиотеки DLL.Минимально это пустая процедура, которая не принимает аргументов и не возвращает ничего, но это может быть любое.
Каждое клиентское приложение, которое будет использовать библиотеки DLL должна вызывать эту процедуру инициализации, при использовании этого подхода.Можно также выбрать этот объект CDynLinkLibrary в DllMain сразу после вызова AfxInitExtensionModule.
Процедура инициализации, следует создать объект в текущей куче приложения, проводной до CDynLinkLibrary данных по библиотеке DLL расширения.Это можно сделать следующим кодом:
extern "C" extern void WINAPI InitXxxDLL()
{
new CDynLinkLibrary(extensionDLL);
}
Обычного имя, InitXxxDLL в этом примере, может быть любым требуется.Для этого не требуется extern "C", однако в этом случае список покупок экспортных упрощает обслуживание.
![]() |
---|
При использовании библиотеки DLL расширения из обычной библиотеки DLL, необходимо экспортировать эта функция инициализации.Эта функция должна вызываться из обычной библиотеки DLL, перед использованием всех классов или ресурсов DLL расширения. |
Экспортировать записи
Простым способом экспортирования классов использовать __declspec(dllimport) и __declspec(dllexport) на каждом классе и глобальной функции нужно экспортировать.Это упрощает многие, но менее эффективно, чем имени каждую точку входа (описаны ниже), поскольку имеется меньше элемента управления на какие функции экспортированы и нельзя экспортировать функции порядковому номеру.TESTDLL1 и TESTDLL2 использующих этот метод, чтобы экспортировать их записи.
Более эффективный метод (и метод, используемый MFCxx.DLL) экспортировать каждая запись вручную путем именования каждую запись в def-файле.Поскольку мы экспортируем селективные нашего экспорты из библиотеки DLL (т е не всех) необходимо решить, какие указанные интерфейсы мы желаем экспортировать.Это будет трудно, поскольку необходимо указать mangled имена компоновщику в форме записей в def-файле.Не экспортировать классы C++ (если они действительно не должен содержать символьную ссылку на него.
Если вы пытались экспортирование классов C++ с помощью DEF-ФАЙЛА, то можно разработать собственное средство, чтобы создать этот список автоматически.Это можно сделать с помощью двухступенный процесс ссылки.Связывание библиотеки DLL раз без экспортов и разрешить компоновщик, чтобы создать файл .MAP.Файл .MAP можно использовать для создания список функций, которые должны быть экспортированы с некоторой изменения порядка, поэтому его можно использовать для создания собственных записей ЭКСПОРТА для файла с расширением def.Список покупок экспортных в MFCxx.DLL и библиотека DLL расширения OLE и базы данных, несколько тысяч по числу, был сформирован с процессом (хотя он не полностью автоматическим и не требует какой-либо настройки руки каждый раз, когда в период времени).
CWinApp.CDynLinkLibrary
Библиотека DLL расширения MFC не имеет CWinApp- производный объект его; вместо этого он должен работать с CWinApp- производным объектом клиентского приложения.Это означает, что клиентское приложение содержит главный цикл обработки сообщений, бездействующий цикл и т д
Если библиотека DLL расширения MFC необходимо поддерживать дополнительные данные для каждого приложения, можно создать новый класс, производный от CDynLinkLibrary и создать его в процедуре InitXxxDLL опишите выше.При запуске текущий список приложения объектов CDynLinkLibrary может проверяться библиотекой DLL для поиска объекта для конкретной библиотеки DLL расширения.
Использование ресурсов в реализации библиотек DLL
Как упоминалось выше, по умолчанию загрузка ресурсов погуляет список объектов CDynLinkLibrary при поиске первый EXE или DLL с запрошенного ресурса.Все API MFC, а также всего внутреннего кода используют AfxFindResourceHandle для обхода список ресурсов для поиска любой ресурс, независимо от того, где она может размещаться.
Если необходимо только загрузить ресурсы из определенного места, использовать API AfxGetResourceHandle и AfxSetResourceHandle для сохранения старого дескриптора и задать новый дескриптор.Перед возвратом к клиентскому приложению убедитесь в том, что старый дескриптор ресурсов восстановлен.Образец TESTDLL2 использует этот подход, при явной загрузке меню.
Проход по списку имеет тот недостаток, что он немного медленнее и требует управления уровнями идентификатора ресурса.Преимуществом является то, что клиентское приложение, связанное с несколькими библиотеками DLL расширения, может использовать любой предоставленный библиотекой DLL ресурс без указания дескриптора экземпляра библиотеки DLL.AfxFindResourceHandle представляет собой API, используемый для прохода по списку ресурсов в поиске заданного совпадения.В эту функцию передаются имя и тип ресурса, будет возвращен дескриптор ресурса, где он был найден в первый раз (или значение "NULL").
Написание приложений, использующих версию DLL
Требований приложения
Приложение, которое использует общедоступную версию MFC должно соответствовать несколько простых правил.
Он должен содержать объект CWinApp и следуют стандартные правила для сообщения нагнетают.
Его необходимо компилировать с параметром обязательного (см. ниже) флагов компилятора.
Он должен быть связан с библиотеками импорта MFCxx.Устанавливая обязательный компилятор пометит, заголовков MFC определяет во время связи, которые библиотека должна связывать с приложением.
Запустить исполняемый файл MFCxx.DLL должно находиться в пути или в каталоге системы windows.
Построение с интегрированной средой разработки
Если используется внутренний файл makefile с большей частью из стандартных значений по умолчанию, то можно легко изменить проект для построения версию DLL.
В следующем шаге предполагается, что имеется правильно, выступающий приложение MFC, связанными с NAFXCWD.LIB (для отладки) и NAFXCW.LIB (для розницы) и требуется преобразовать для использования общей версии библиотеки MFC.Запустите среду Visual C++ и имеется файл внутреннего проекта.
- В меню Проекты, нажмите кнопку Свойства.На странице Общие в Значения по умолчанию для проекта задайте классы Microsoft foundation в Использовать MFC в общей DLL (MFCxx (д) .dll).
Построение с NMAKE)
При использовании внешнюю функцию файл makefile Visual C++ или использовать NMAKE напрямую, то изменения в файле makefile для поддержки параметров компилятора и компоновщика
Обязательные флаги компилятора:
- /D_AFXDLL /MD
/D_AFXDLL
Стандартным заголовков MFC выполняется этот символ быть определены:
- /MD
Приложение должно использовать версию DLL библиотеки времени выполнения C
Все остальные флаги компилятора за значениями по умолчанию MFC (например, _DEBUG для отладки).
Правка список библиотек компоновщика.Измените NAFXCWD.LIB к MFCxxD.LIB и измените NAFXCW.LIB к MFCxx.LIB.Замените LIBC.LIB с помощью библиотеки MSVCRT.LIB.Как и любой другой библиотекой MFC важно, чтобы MFCxxD.LIB помещенное before любой библиотеки среды выполнения C.
При необходимости добавьте /D_AFXDLL и в рознице и отладки параметры компилятора ресурсов, в действительности будет компилироваться (ресурсов с /R).Это делает в окончательное исполняемое маленькое, совместное использование ресурсов, которые присутствуют в библиотеке DLL MFC.
Полное перестроение необходимо после того, как эти изменения выполняются.
Построение образца
Большинство примеров программ MFC можно построить из Visual C++ или от общего ФАЙЛА MAKEFILE NMAKE-совместимого из командной строки.
Чтобы преобразовать какой-либо из этих примеров для использования MFCxx.DLL можно загрузить файл .MAK в Visual C++ и задать параметры проекта, как описано выше.При использовании построение программы NMAKE, можно указать «AFXDLL=1» в командной строке NMAKE и построит образца с помощью общие библиотеки MFC.
Образец MFC Основных понятий расширенная DLLHUSK строится с версией MFC DLL.В этом образце показано, как построить приложение не только связанное с MFCxx.DLL, но она также демонстрируются другие функции параметра упаковки библиотека DLL MFC, как библиотека DLL расширения MFC, описанные далее в этой технической заметку.
Упаковочный примечания
Розничная версия библиотеки DLL (MFCxx [U] .dll) свободно распространяемый пакет.Отладочная версия библиотеки DLL свободно распространяемый пакет не и должна использоваться только в процессе разработки приложения.
Библиотека отладки предоставляемых с данными об отладке.С помощью отладчика Visual C++, можно отслеживать выполнение приложения, а также библиотеки DLL.Библиотека DLL edition (MFCxx [U] .dll) не содержат сведения для отладки.
Если вы настраиваете или перестроении библиотеки DLL, необходимо вызывать их значение, отличное от «MFCxx» файл MFCDLL.MAK MFC SRC описывает параметры построения и содержит логику для переименования библиотеки DLL.Переименование файлов является обязательным, поскольку эти библиотеки DLL может совместно использоваться для многих приложений MFC.Having пользовательскую версию DLL MFC замените эти установлены в системе может нарушить другое приложение MFC с использованием общих библиотек DLL MFC.
Перестроение библиотеки DLL MFC не рекомендуется.
MFCxx.DLL реализуется как
Следующий раздел описывает способ использования библиотеки DLL MFC (MFCxx.DLL и MFCxxD.DLL) реализовано.Здесь также понимание сведения не важны, если требуется использовать библиотеку DLL MFC с приложением.Сведения здесь не требуются для понимания, как создать библиотеку DLL расширения MFC, но понимание эту реализацию помогает написать собственные библиотеки DLL.
Общие сведения о реализации
Библиотека DLL MFC являются особый случай библиотеки DLL расширения MFC, как описано выше.Он имеет большой объем экспортов больших объемов классов.Несколько дополнительных факторов мы делаем в MFC DLL, которые делают его еще более специальными, чем обычный библиотеки DLL расширения.
Win32 выполняет большую часть работы
Шестнадцатиразрядной версии MFC были требуются несколько специальных методов, в том числе данные для каждого приложения для сегмента стека, созданных специальным сегментах код сборки несколько 80x86, контекстах исключения в-процесса и других методах.Win32 непосредственно поддерживает данные в-процесса в DLL, - требуется большая часть времени.В большинстве случаев MFCxx.DLL только NAFXCW.LIB упакованные в DLL.При рассмотрении исходный код MFC оказывается весьма небольшое количество _AFXDLL #ifdef, поскольку очень мало особых случаях, которые необходимо делать.Особых случаях, в частности, существует ли работать с Win32 в Windows 3.1 (в противном случае как Win32s).Win32s не поддерживает данные библиотеки DLL в-процесса непосредственно поэтому библиотека DLL MFC следует использовать поток-местные Win32 API хранения (TLS) для получения процесс локальные данные.
Влияние на источники дополнительных файлов библиотек
Влияние версии _AFXDLL в источниках и обычных заголовков библиотек классов MFC, касающиеся небольш.Нерегламентированный файл версии (AFXV_DLL.H), а также дополнительный файл заголовка (AFXDLL_.H) главным заголовком AFXWIN.H.Заголовок AFXDLL_.H включает класс CDynLinkLibrary как и другие сведения о реализации приложений _AFXDLL, так и библиотека DLL расширения MFC.Заголовок AFXDLLX.H служит для построения библиотеки DLL расширения MFC (см. выше). дополнительные сведения.
Обычные источники в библиотеке MFC в MFC SRC имеют некоторый дополнительный код под #ifdef условные _AFXDLL.Дополнительный файл источника (DLLINIT.CPP) содержит дополнительный код инициализации библиотеки DLL, а другой клей для общей версией MFC.
Построение общедоступную версию MFC предоставляются дополнительные файлы.(См. далее дополнительные сведения о построении библиотеки DLL).
2 Файла с расширением def используются для экспорта точки входа DLL MFC для отладки (MFCxxD.DEF) и освобождает версии (MFCxx.DEF) DLL.
Rc-файл (MFCDLL.RC) содержит все стандартные ресурсы MFC и ресурс VERSIONINFO для библиотеки DLL.
Указывается, что позволяет файл .CLW (MFCDLL.CLW) для просмотра классов MFC с использованием ClassWizard.Примечание. эта функция не определена до версии DLL MFC.
Управление памятью
Приложения с использованием MFCxx.DLL используется общий механизм распределения предоставленный MSVCRTxx.DLL, общую библиотеку DLL памяти среды выполнения C.Приложение, все библиотеки DLL расширения и хорошо, как сами DLL MFC использует этот выделения общей памяти.С помощью общего библиотеки DLL для выделения памяти в MFC DLL могут распределить память освобождается или наоборот, более поздней версии приложения.Поскольку приложение и библиотека DLL должны использовать один и тот же распределитель, не следует переопределить C++ operator new глобального или operator delete.Те же правила, которые применяются с процедур времени выполнения c (например, malloc выделения памяти, realloc, free и др.).
Порядковые номера и __declspec (dllexport) класса и именовании библиотек DLL
Не рекомендуется использовать функциональные возможности class**__declspec(dllexport)** компилятора C++.Вместо этого список экспортов включен с источниками библиотеки классов (MFCxx.DEF и MFCxxD.DEF).Только эти выберите набор точек входа (функции и данные) экспортирован.Другие символы, такие как функции или классы реализации MFC закрытые, не экспортированы все экспортам внесены порядковому номеру без имени строки в резиденте или нерезидентной таблице имен.
Использование class**__declspec(dllexport)** может быть жизнеспособным вариантом для построения меньших библиотеки DLL, но в случае больших библиотек DLL MFC, по умолчанию в качестве экспортирования механизм имеет ограничения эффективности и емкости.
Это означает, что все, что мы можем пакет большое количество функций в выпуске MFCxx.DLL, только вокруг 800 КБ без компрометировать много выполнения или скорость загрузки.Не использовалось MFCxx.DLL было бы 100K больше этот метод.Кроме того, это делает возможным добавлять дополнительные точки входа в конце файла с расширением def для разрешения простого элемента управления версиями без компрометировать эффективность скорости и размера экспортироваться порядковым номером.Изменения основной номер версии библиотеки классов MFC изменяется имя библиотеки.Иными словами, MFC30.DLL распространения библиотеки DLL, содержащий версию 3.0 библиотеки классов MFC.Обновление этого DLL) сообщает, в постулативном DLL MFC 3,1, будет иметь имя MFC31.DLL.Опять же, при изменении исходный код MFC для создания пользовательской версии библиотек DLL MFC, используйте другое имя (предпочтительно «и без MFC» в имени).