Эта записка описывает, как вы можете использовать MFCxx.DLL и MFCxxD.DLL (где x — номер версии MFC) совместно используемые библиотеки динамической компоновки с приложениями MFC и библиотеки DLL расширения. Дополнительные сведения о регулярных библиотек DLL содержатся в разделе Использование MFC как часть библиотеки DLL.
Эта техническая записка охватывает три аспекта библиотек DLL. Две последние предназначены для более опытных пользователей:
Если вы заинтересованы в создании библиотеки DLL с помощью MFC, который можно использовать с приложениями не MFC (это называется обычной DLL), обратитесь к технической записке 11.
Обзор поддержки MFCxx.DLL: терминология и файлов
Обычная библиотека DLL: обычная библиотека DLL используется для построения автономных DLL с помощью некоторых из классов MFC. Интерфейсы через границу App/DLL являются интерфейсы «C», и клиентское приложение не нужно быть приложением MFC.
Это версия DLL поддержки поддерживает в MFC 1.0. Он описан в технической записке 11 и MFC концепции перспективных образцов DLLTRACE.
Примечание В Visual C++ версии 4.0, термин USRDLL является устаревшим и был заменен обычной библиотеки DLL, которые статически связана с MFC. Вы также можете строить обычную библиотеку DLL, динамически связывает с MFC.
MFC 3.0 (и выше) с новой функциональности, включая классы OLE и база данных поддерживает обычные библиотеки DLL.
AFXDLL: это также называется общей версии библиотек MFC. Это новый добавлена в MFC 2.0 поддержка библиотеки DLL. Сама библиотека MFC в ряде библиотек DLL (описываются ниже) и клиентское приложение или DLL динамически связывает библиотеки DLL, которые он требует. Интерфейсы через границу приложение/DLL, C + +/ интерфейсов классов MFC. Клиентское приложение должно быть приложением MFC. Это поддерживает все функции MFC 3.0 (excption: UNICODE не поддерживается для классов базы данных).
Примечание Состоянию на Visual C++ версии 4.0 этот тип библиотеки DLL называется «DLL расширения.»
Эта записка будет использовать MFCxx.DLL сослаться на все заданные MFC DLL, которая включает в себя:
Примечание MFCSxx [U] [D].LIB библиотеки используются в совместно с MFC общих библиотек DLL. Эти библиотеки содержат код, который должна быть статически связана с приложением или DLL.
Приложение ссылки на соответствующие библиотеки импорта:
«Библиотеки DLL расширения MFC» представляет собой библиотеку DLL, на MFCxx.DLL (и/или другие MFC shared библиотеки DLL). Здесь в ногах архитектура компонентов MFC. Если вы полезный класс, производный от класса MFC, или построить еще один MFC-как инструментарий, можно поместить в библиотеку DLL. DLL использует MFCxx.DLL, равно как и в конечном итоге клиентское приложение. Это позволяет повторно листа классов, многократно используемых базовых классов и документ многократно используемых представления классов.
Примечаниеnbsp; Нет необходимости для связи с MFCOxx [U] D, D MFCDxx [U], MFC&Nxx [U] D Debug библиотеки или если приложение не использует MFC/OLE, база данных или сетевые классы соответственно.
Доводы за и против
Почему должны вы использовать общую версию MFC?
Почему вам не следует использовать общую версию MFC:
Библиотека DLL расширения MFC является библиотекой DLL, содержащей классы и функции, написанные украшали функциональность классов MFC. Поддержка OLE и база данных отладки библиотек DLL (MFCOxxD.DLL и MFCDxxD.DLL) являются примерами DLL расширения MFC в том, что они используют MFCxxD.DLL. Библиотека DLL расширения MFC использует общие DLL MFC таким же образом, приложение использует его, с несколько дополнительных соображений:
Эти соображения описаны более подробно ниже. Вам следует также указывать пример концепции перспективных MFC DLLHUSK так, как это иллюстрирует
Клиентское приложение и все библиотеки DLL расширения должны использовать ту же версию MFCxx.DLL. Вы должны следовать Конвенции MFC DLL и обеспечивают как отладки и розничная (/ release) версии библиотеки DLL расширения. Это позволяет клиентские программы для создания отладочных и распространяемых версий своих приложений и связать их с соответствующим отладки или розничной версии DLL-файлов.
Примечание Из-за проблемы искажения и экспорта имен C++, список экспорта из библиотеки DLL расширения может быть различным у отладочных и распространяемых версий той же библиотеки DLL и библиотек DLL для различных платформ. MFCxx.DLL розничной около 2000 экспортировала точки входа; Отладка MFCxxD.DLL около 3000 экспортировала точки входа.
Краткие сведения по управлению памятью
В разделе «Управление памятью,» в конце настоящей технической записки, описывает реализацию MFCxx.DLL с общей версии MFC. Информацию, которую вам нужно знать для реализации просто расширение DLL описан здесь.
MFCxx.DLL и все библиотеки DLL расширения, загруженного в адресное пространство клиентского приложения будет использовать же распределитель памяти, Загрузка ресурсов и другие государства «глобальные» MFC, как если бы они находились в том же приложении. Это важно, потому что библиотек MFC DLL обычным библиотекам DLL, статически связанным с MFC делать как раз обратное и что каждая DLL выделения из пула памяти.
Если памяти библиотекой DLL расширения, то что можно свободно распределение памяти с любым другим объектом, выделенных веб-приложений. Кроме того если приложение, использующее разделяемые библиотеки MFC аварий, защиты операционной системы будет поддерживать целостность любого другого приложения MFC, совместное использование библиотеки DLL.
Аналогичным образом другие «глобальные» MFC государства, такие как текущий исполняемый файл для загрузки ресурсов, также совместно клиентское приложение и все библиотеки DLL расширения MFC, а также MFCxx.DLL сам.
Создание библиотеки DLL расширения
AppWizard можно использовать для создания проекта DLL расширения MFC, и он будет автоматически генерировать соответствующие параметры компилятора и компоновщика. Он был также генерировать функцию DllMain , которую можно изменить.
При преобразовании существующего проекта для библиотеки DLL расширения MFC, начните с стандартные правила для создания приложения с использованием общей версии MFC, а затем выполните следующие действия:
Изменение файлов заголовков
Цель расширения DLL обычно экспортировать некоторые общие функциональные возможности в одно или несколько приложений, которые можно использовать эту функциональность. Это сводится к экспортировать классы и глобальные функции, которые доступны для клиентских приложений.
Для того чтобы сделать это необходимо убедиться, что каждый из функций-членов отмечается как импорта или экспорта в случае необходимости. Это требует специального объявления: __declspec(dllexport) и __declspec(dllimport). Когда ваши классы используются клиентскими приложениями, они должны быть объявлены как __declspec(dllimport). При построении библиотеки DLL, сам расширения они должны быть объявлены как __declspec(dllexport). Кроме того функции должны быть фактически экспорт, таким образом, чтобы клиентские программы привязка к ним во время загрузки.
Чтобы экспортировать весь класс, используйте AFX_EXT_CLASS в определении класса. Этот макрос определяется в рамках как __declspec(dllexport) , когда _AFXDLL и _AFXEXT определена, но определяется как __declspec(dllimport) , когда _AFXEXT не определен. _AFXEXT как описано выше, определяется только при построении библиотеки DLL расширения. Например:
класс AFX_EXT_CLASS CExampleExport: государственные CObject
{... класс определения...}
Не экспортировать весь класс
Иногда может потребоваться экспортировать только отдельных необходимых членов класса. Например, если вы экспортируете CDialog-производного класса, вам возможно потребуется экспортировать только конструктора и вызов DoModal . Вы можете экспортировать эти элементы с помощью библиотеки DLL.DEF-файла, но его можно также использовать AFX_EXT_CLASS во многом так же, как на индивидуальных членов, котор вам нужно экспортировать.
Например:
класс CExampleDialog: государственные CDialog
{
общественности:
AFX_EXT_CLASS CExampleDialog();
AFX_EXT_CLASS int DoModal();
/ / Отдых определения класса
.
.
.
}
Когда вы сделаете это, вы можете столкнуться дополнительную проблему того, что больше не экспорт всех членов класса. Проблема заключается в том, что работа макросов MFC. Несколько вспомогательных макросов MFC объявляют или определяют члены данных. Таким образом эти члены данных должны также быть экспортированы из библиотеки DLL.
Например макрос DECLARE_DYNAMIC определяется следующим при построении библиотеки DLL расширения:
# define DECLARE_DY&NAMIC(class_name) \
защита: \
nbsp; статический CRuntimeClass * Паскаль _GetBaseClass(); \
государственные: \
класс статического AFX_DATA, объявляет CRuntimeClass ## class_name; \
виртуальный CRuntimeClass * GetRuntimeClass() const; \
Строка, которая начинается "статического AFX_DATA, объявляет" о статическом объекте внутри класса. Чтобы правильно экспортировать класс и получить доступ к информации времени выполнения с клиента.EXE, необходимо экспортировать статический объект. Так как статический объект объявлен с модификатором AFX_DATA, объявляет, требуется только определение AFX_DATA, объявляет быть __declspec(dllexport) при построении библиотеки DLL и определить его как __declspec(dllimport) при создании вашего клиента исполняемый.
Как указывалось выше, AFX_EXT_CLASS уже определен таким образом. Так что вам просто нужно пересмотреть AFX_DATA, объявляет быть такими же, как AFX_EXT_CLASS вокруг вашего определения класса.
Например:
nbsp; # undef AFX_DATA, объявляет
# определение AFX_DATA, объявляет AFX_EXT_CLASS
класс CExampleView: государственные CView
{
DECLARE_DY&NAMIC()
/ /... класса определение...
};
# undef AFX_DATA, объявляет
# определение AFX_DATA, объявляет
MFC всегда использует символ AFX_DATA, объявляет о элементов данных, которые он определяет в пределах своих макросы, поэтому этот метод будет работать для всех подобных сценариев. К примеру, он будет работать для DECLARE_MESSAGE_MAP.
Примечание При экспортировании всего класса, а не отдельных членов класса, статические члены данных автоматически экспортируются.
Можно использовать одинаковые технологии для автоматически экспортировать CArchive извлечения оператора для классов, которые используют DECLARE_SERIAL и IMPLEMENT_SERIAL макросов. Экспортировать оператор архива, Брекетинг объявления класса (в.H-файл) с помощью следующего кода:
# undef AFX_API
# define AFX_API AFX_EXT_CLASS
lt; ваши объявления класса здесь >
# undef AFX_API
# define AFX_API
Ограничения _AFXEXT
Препроцессоре символ _AFXEXT можно использовать для расширения DLL, пока вы не имеют несколько уровней DLL расширения. Если у вас есть расширение DLL, которых требуется или производными от классов в собственное расширение DLL, которые затем являются производными от классов MFC, чтобы избежать двусмысленности необходимо использовать собственный символ препроцессора.
Проблема заключается в том, что в Win32, необходимо явно объявлять любые данные как __declspec(dllexport) если это экспорт из DLL и __declspec(dllimport) , если он хочет быть импортированы из библиотеки DLL. При определении _AFXEXTзаголовков MFC убедитесь, что AFX_EXT_CLASS правильно в.
Когда у вас есть несколько слоев, один символ как AFX_EXT_CLASS недостаточно, так как DLL расширения может быть экспортировать новые классы, а также импорт других классов из другой библиотеки DLL расширения. Для решения этой проблемы, используйте специальный препроцессоре символ, который означает, что вы создаете DLL или с использованием библиотеки DLL. Например представьте себе библиотек два расширения, A.DLL и B.DLL. Каждый из них экспорта некоторых классов в года хиджры и B.H, соответственно. B.dll использует классы из A.DLL. Заголовочные файлы выглядят примерно следующим образом:
/ / ГОДА ХИДЖРЫ
# ifdef A_IMPL
# define CLASS_DECL_A __declspec(dllexport)
# else
# define CLASS_DECL_A __declspec(dllimport)
# endif
класс CLASS_DECL_A CExampleA: государственные CObject
{... класс определения...};
/ / B.H
# ifdef B_IMPL
# define CLASS_DECL_B __declspec(dllexport)
# else
# define CLASS_DECL_B __declspec(dllimport)
# endif
класс CLASS_DECL_B CExampleB: государственные CExampleA
{... класс определения...}
При построении A.DLL, он построен с /D A_IMPL и при построении B.DLL, он построен с /D B_IMPL. С помощью отдельных символов для каждой библиотеки DLL, CExampleB экспортируется и CExampleA импортируются при построении B.DLL. CExampleA экспорт при построении A.DLL и импортируются при использовании B.DLL (или другой клиент).
Этот тип иерархическое представление не может быть сделано при использовании встроенных AFX_EXT_CLASS и _AFXEXT препроцессоре символов. Техника решает эту проблему способом, не отличным от который используется классами MFC при построении его DLL расширения OLE, базы данных и сети.
Не экспортировать весь класс
Опять же необходимо проявлять особую осторожность при экспорте не целого класса. Вы должны обеспечить правильно экспорт необходимых данных элементов, созданных макросов MFC. Это может быть сделано путем пересматривают AFX_DATA, объявляет вашего конкретного класса макрос. Это должно быть сделано в любое время, не экспортируется весь класс.
Например:
/ / ГОДА ХИДЖРЫ
# ifdef A_IMPL
nbsp; # define CLASS_DECL_A _declspec(dllexport)
# else
# define CLASS_DECL_A _declspec(dllimport)
# endif
# undef AFX_DATA, объявляет
# определение AFX_DATA, объявляет CLASS_DECL_A
класс CExampleA: государственные CObject
{
DECLARE_DY&NAMIC()
CLASS_DECL_A int SomeFunction();
определение //Class.
.
.
};
# undef AFX_DATA, объявляет
# определение AFX_DATA, объявляет
DllMain
Ниже приведен точный код, который следует поместить в ваш основной исходный файл для библиотеки DLL расширения. Он должен прийти после того, как стандарт включает. Обратите внимание, что при использовании AppWizard для создания начальных файлов для библиотеки DLL расширения, снабжает DllMain для вас.
# include «afxdllx.h»
статический AFX_EXTE&NSION_MODULE extensionDLL;
extern «C» int APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
nbsp; Если (dwReason == процессе)
{
/ / Однократная инициализация библиотеки DLL расширения КРП (!AfxInitExtensionModule)
extensionDLL, hInstance))
Возвращает 0;
/ / TODO: выполняют другие задачи инициализации
}
иначе если (dwReason == DLL_PROCESS_DETACH)
{
/ / DLL расширения каждого процесса прекращения
AfxTermExtensionModule(extensionDLL);
/ / TODO: выполняют другие задания очистки
}
возвращение 1; / / ОК
}
Призыв к AfxInitExtensionModule захватывает модули времени выполнения классы (CRuntimeClass структуры), а также его объекту фабрики (объектыCOleObjectFactory ) для использования позже при создании объекта CDynLinkLibrary . (Необязательно) призыв к AfxTermExtensionModule позволяет MFC для очистки DLL расширения, когда каждый процесс отсоединяется (что случается при завершении процесса, или когда DLL выгружается из вызов FreeLibrary ) из библиотеки DLL расширения. Поскольку большинство расширение библиотеки DLL не загружаются динамически (как правило, они связаны через свои библиотеки импорта), вызов AfxTermExtensionModule обычно не стоит.
Если приложение загружает и освобождает DLL расширения динамически, не забудьте вызвать AfxTermExte&nsionModule как показано above.nbsp; Кроме того, не забудьте использовать AfxLoadLibrary и AfxFreeLibrary (вместо функций Win32 LoadLibrary и FreeLibrary) Если ваше приложение использует несколько потоков. С помощью AfxLoadLibrary и AfxFreeLibrary гарантирует, что код запуска и завершения работы, который выполняется, когда загружается и выгружается DLL расширения не коррумпированные глобальные состояния MFC.
Заголовочный файл AFXDLLX.H содержит специальные defintions для структур, используемых в расширение DLL, такие как определение для AFX_EXTENSION_MODULE и CDynLinkLibrary.
Глобальный extensionDLL должна быть объявлена как показано. В отличие от 16-разрядной версии MFC можно выделить память и вызвать функции MFC в это время, так как MFCxx.DLL полной инициализации к времени, когда DllMain вызывается событием.
Совместное использование ресурсов и классы
Простой библиотеки DLL расширения MFC требуется экспортировать только несколько функций низкой пропускной способностью в клиентском приложении и ничего более. Более интенсивное DLL пользовательского интерфейса может потребоваться экспортировать ресурсов и классы C++ в клиентское приложение.
Экспорт ресурсов осуществляется через список ресурсов. В каждом приложении это однонаправленный список объектов CDynLinkLibrary . При поиске ресурса большинство стандартных реализаций MFC, что загрузка ресурсов выглядят первый в текущем модуле ресурсов (AfxGetResourceHandle) и если ходить списку объектов CDynLinkLibrary , пытаясь загрузить запрошенный ресурс не найден.
Динамического создания объектов C++, заданное имя класса C++ аналогично. Механизм десериализации MFC объекта должен иметь все объекты CRuntimeClass , зарегистрированные таким образом, чтобы она может восстановить путем динамического создания объектов C++ нужного типа, на основе того, что было сохранено ранее.
Если вы хотите, чтобы клиентское приложение для использования классов в библиотеке DLL расширения, которые являются DECLARE_SERIAL, то вам нужно экспортировать классы видимым клиентскому приложению. Это делается путем прохождения CDynLinkLibrary списка.
По концепции перспективных MFC образца DLLHUSKсписок выглядит примерно так
головной - > DLLHUSK.EXE - или - DLLHUSK.EXE
| |
TESTDLL2.DLL TESTDLL2.БИБЛИОТЕКА DLL
| |
ВЫПОЛНЯЕТСЯ.DLL ВЫПОЛНЯЕТСЯ.БИБЛИОТЕКА DLL
| |
MFCO42D.DLL |
| |
MFCD42D.DLL |
| |
MFC42D.DLL MFC42.БИБЛИОТЕКА DLL
MFCxx.DLL обычно последний на ресурс и список классов. MFCxx.DLL включает в себя все стандартные ресурсы MFC, включая оперативное строк для всех идентификаторов стандартных команд. Размещение на хвост списка позволяет библиотек DLL и клиентское приложение само по себе не имеют свою собственную копию стандартных ресурсов MFC, но полагаться на общих ресурсах в MFCxx.DLL вместо.
Объединение ресурсов и имена классов всех библиотек DLL в пространстве имен клиентского приложения имеет недостаток, что вы должны быть осторожным какие идентификаторы или имена можно выбрать. Конечно, можно отключить эту функцию, не экспортировать ваши ресурсов или объекта CDynLinkLibrary клиентскому приложению. Пример DLLHUSK управляет пространством имен общедоступного ресурса с помощью нескольких файлов заголовков. Просмотреть техническое примечание 35 дополнительные советы по использованию файлов общего ресурса.
Инициализация библиотеки DLL
Как упоминалось выше, будет обычно требуется для создания объекта CDynLinkLibrary для того чтобы экспортировать ваши ресурсы и классы клиентскому приложению. Необходимо будет предоставить экспортированных отправной точки для инициализации библиотеки DLL. Как минимум это рутинные void, не принимающего аргументов и ничего не возвращает, но это может быть все, что вам нравится.
Каждое клиентское приложение, которое хочет использовать библиотеку DLL должен вызывать эта процедура инициализации, если вы используете этот подход. Возможно также выделить этот объект CDynLinkLibrary в вашем DllMain сразу после вызова AfxInitExtensionModule.
Процедура инициализации необходимо создать объект CDynLinkLibrary в куче текущего приложения, проводные до расширения DLL информацию. Это может быть сделано следующим:
extern «C» extern аннулировать WI&NAPI InitXxxDLL()
{
nbsp; новый CDynLinkLibrary(extensionDLL);
}
Обычного имени, InitXxxDLL в этом примере, может быть что-нибыдь вы хотите. Она не должна быть extern “C” , но делает это так делает проще поддерживать список экспорта.
Примечание Если вы используете DLL из обычной библиотеки DLL расширения, необходимо экспортировать эту функцию инициализации. Эта функция должна вызываться из обычной библиотеки DLL, прежде чем использовать какие-либо классы библиотеки DLL расширения или ресурсы.
Экспорт записей
Простой способ экспорта ваших классов должен использовать __declspec(dllimport) и __declspec(dllexport) на каждый класс и глобальной функции, которые вы хотите экспортировать. Это делает его намного проще, но менее эффективен, чем именование каждой точки входа (описываются ниже), так как у вас меньше контроля над экспортируются какие функции и функции нельзя экспортировать по порядковому номеру. Это метод, который выполняется и TESTDLL2 используется для экспорта их записи.
Более эффективный метод (и метод, используемый MFCxx.DLL) — экспорт каждой записи вручную, назвав каждой записи в.DEF-файл. Так как мы экспортируем выборочного экспорта из нашей библиотеки DLL (то есть, не все), мы должны определить какие конкретные интерфейсы, мы желаем для экспорта. Это трудно, так как искаженное имена компоновщику необходимо указать в виде записей в.DEF-файл. Не следует экспортировать какие-либо классы C++ Если вам действительно нужно иметь символическую ссылку для него.
Если вы пробовали экспорта C++ классов с.DEF файла, прежде чем, вы можете разработать инструмент для создавать этот список автоматически. Это можно сделать с помощью процесса связи две стадии. Связать библиотеку DLL с экспорт, и позволить компоновщик для генерации.Файл карты. С.Файл карты может использоваться для создания списка функций, которые должны быть экспортированы, поэтому файл с некоторыми munging, она может использоваться для создания ваших экспорта записей для вашего.DEF-файл. Экспорт списка MFCxx.DLL и OLE и библиотек расширения баз данных, несколько тысяч в номер, был сгенерирован с таким процессом (хотя и это не является полностью автоматизирована и требует некоторых ручной настройки каждый раз в то время).
CWinApp vs. CDynLinkLibrary
Библиотека DLL расширения MFC не имеет CWinApp-производный объект своих собственных; Вместо этого он должен работать с CWinApp-производный объект клиентского приложения. Это означает, что клиент приложение имеет основной конвейер сообщений, простой цикл и так далее.
Если библиотека DLL расширения MFC должен поддерживать дополнительные данные для каждого приложения, можно создать новый класс, производный от CDynLinkLibrary и создать его в InitXxxDLL, обычной описали выше. При запуске, библиотеки DLL можно проверить текущее приложение список объектов CDynLinkLibrary найти для этого конкретного расширения DLL.
Использование ресурсов в вашей реализации DLL
Как упоминалось выше, загрузки ресурсов по умолчанию будут ходить список объектов CDynLinkLibrary ищет первый EXE или DLL, которая имеет запрошенный ресурс. Все API-интерфейсов MFC, а также внутренний код использует AfxFindResourceHandle ходить списка ресурсов, чтобы найти какой-либо ресурс, независимо от того, где он может находиться.
Если вы хотите только загружать ресурсы из определенного места, используйте API AfxGetResourceHandle и AfxSetResourceHandle сохранить старый ручки и задать новый маркер. Не забудьте восстановить старый дескриптор ресурса, прежде чем вы вернетесь к клиентскому приложению. TESTDLL2 использует этот подход явно загрузки в меню.
Прогулки в списке имеет недостатки, он немного медленнее и требует управления диапазонами Идентификатор ресурса. Это имеет то преимущество, что клиентское приложение, которое связывает несколько DLL-библиотек расширения можно использовать любой DLL-если ресурс без необходимости указывать экземпляр обработчика DLL. AfxFindResourceHandle это API используется для прогулок списка ресурсов для поиска конкретного матча. Он принимает имя и тип ресурса и возвращает дескриптор ресурса, где впервые было установлено (или NULL).
Требования приложений
Приложение, использующее общую версию MFC необходимо выполнить несколько простых правил:
Здание с среды разработки
Если вы используете внутренний makefile с большинством стандартных значений по умолчанию, вы можете легко изменить проект для построения версию библиотеки DLL.
Следующий шаг предполагает, что у вас правильно функционирующих приложений MFC, связанные с NAFXCWD.Библиотека (для отладки) и NAFXCW.LIB (для розничной торговли) и вы хотите его использовать общую версию библиотеки MFC. Вы работаете в среде Visual C++ и внутреннего проекта файл.
Здание с 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. Добавляйте MFCOxx[U]D.LIB, MFCDxx[U]D.LIB и MFCNxx[U]D.LIB (требуется для с использованием MFC/OLE, базы данных или сетевых классов). Замените LIBC.LIB с MSVCRT.ЛИБ. Как с любой другой библиотекой MFC важно включить MFCxxD.LIB прежде чем любой библиотеки времени выполнения c.
При необходимости добавьте /D_AFXDLL как ваши розничные и отладки параметры компилятора ресурсов (тот, который фактически собирает ресурсы с/r). Это делает ваш окончательный исполняемый файл меньше совместного использования ресурсов, которые присутствуют в библиотеках DLL MFC.
После того, как эти изменения вносятся требуется полная перестройка.
Создание образцов
Большинство программ MFC, образец может быть построен из Visual C++ или с общей NMAKE-совместимых MAKEFILE из командной строки.
Чтобы преобразовать любой из этих образцов для использования MFCxx.DLL, вы можете загрузить.Мак file в Visual C++ и задать параметры проекта, как описано выше. Если вы используете NMAKE сборки, можно указать "AFXDLL = 1" на NMAKE командной строки и что будет строить примера с использованием общей библиотеки MFC.
Пример концепции перспективных MFC DLLHUSK построен с версии библиотеки DLL MFC. В этом примере не только показывает, как создать приложение связано MFCxx.DLL, но он также иллюстрирует другие функции MFC DLL варианта упаковки например библиотеки DLL расширения MFC, описанных далее в этой технической записке.
Упаковка примечания
Розничная версия библиотек DLL (MFCxx [U].DLL) являются свободно распространяемыми. Отладочная версия библиотеки DLL не являются свободно распространяемых и должны использоваться только во время разработки приложения.
Отладки библиотек DLL предоставляются с отладочной информацией. С помощью отладчика Visual C++, вы можете отслеживать выполнение вашего приложения, а также библиотеки DLL. Релиз библиотеки DLL (MFCxx [U].DLL) не содержит отладочную информацию.
Если изменить или восстановить файлы DLL, то следует вызывать их что-то за исключением «MFCxx» The MFC SRC файла MFCDLL.Мак описывает параметры сборки и содержит логику для переименования DLL. Это правило также применяется к MFC/OLE, базы данных и сети библиотек DLL, которые строятся на MFCOLE.МАК, MFCDB.Мак и MFCNET.Мак, соответственно. Переименование файлов является необходимым, поскольку эти библиотеки DLL являются потенциально многими приложениями MFC. Имея пользователями настраиваемой версии библиотек DLL MFC заменить те, установленных в системе может нарушить другое приложение MFC с использованием общих библиотек DLL MFC.
Восстановление библиотеки MFC DLL не рекомендуется использовать.
В следующем разделе описываются, как реализован DLL MFC (MFCxx.DLL и MFCxxD.DLL). Понимание подробности здесь не важно, если вы хотите сделать это использовать библиотеку DLL MFC с приложением. Подробности здесь не являются необходимыми для понимания того, как написать DLL расширения MFC, но понимание этой реализации может помочь вам написать свой собственный DLL.
Обзор выполнения
Библиотека DLL MFC действительно представляет собой особый случай DLL расширения MFC, как описано выше. Она имеет очень большое количество экспорта для большого числа классов. Существует несколько дополнительных вещей, что мы делаем в библиотеке DLL MFC, которые делают его еще более специальных чем обычной DLL расширения.
Win32 делает большую часть работы
16-Разрядной версии MFC требуется ряд специальных методов, включая данные-app на сегмент стека, специальные сегменты, созданный код 80 x 86 Ассамблея, контекстов каждого процесса исключения и другие методы. Win32 непосредственно поддерживает данные одного процесса в DLL, которая является тем, что большую часть времени. В основном MFCxx.DLL это просто NAFXCW.LIB, упакованного в DLL. Если вы посмотрите на исходный код MFC, вы сможете найти очень мало # ifdef _AFXDLL, поскольку существует очень мало особых случаев, которые должны быть сделаны. Особые случаи, которые есть специально заниматься Win32 на Windows 3.1 (иначе известная как Win32s). Win32s не данных DLL поддержки каждого процесса непосредственно таким образом MFC DLL должна использовать локальной памяти потока (TLS) интерфейсы API Win32 для получения локальных данных процесса.
Влияние на библиотеки источников, дополнительные файлы
Влияние _AFXDLL версии на обычный источники библиотеки классов MFC и заголовков является относительно незначительным. Существует специальная версия файл (AFXV_DLL.H), так и дополнительный заголовочный файл (AFXDLL_.H) включены основные AFXWIN.H заголовок. AFXDLL_.H заголовка включает CDynLinkLibrary класс и другие детали реализации _AFXDLL приложений и библиотек DLL расширения MFC. AFXDLLX.H заголовка предоставляется для создания библиотеки DLL расширения MFC (см. выше).
Регулярные источники для библиотеки MFC в MFC SRC имеют дополнительный условный код под _AFXDLL # ifdef. Еще один источник файла (DLLINIT.НПК) содержит дополнительный код инициализации библиотеки DLL и другие клея для общей версии MFC.
Для того чтобы построить общую версию MFC, предоставляются дополнительные файлы. (См. ниже информацию о том, как построить DLL.)
Построение библиотеки DLL MFC
Восстановление MFC DLL намеренно сложным, так что вы думаете дважды (или три раза) прежде чем делать это. Если вы понимаете возможные проблемы упаковки и перераспределения ограничения, описанные ниже и вы по-прежнему очень нужна перестройка MFC DLL, вы можете.
MFCDLL.Мак файл будет строить отладки DLL с информация CodeView:
NMAKE /f mfcdll.mak DEBUG = 1 LIBNAME = MYMFC
MFCDLL.Мак файл будет строить версии DLL без информация CodeView:
NMAKE /f mfcdll.mak DEBUG = 0 LIBNAME = MYMFC
(аналогично, использовать MFCOLE.МАК, MFCDB.Мак и MFCNET.Мак построить MFCOxxD.DLL, MFCDxxD.DLL и MFCNxxD.DLL — библиотеки DLL, содержащие MFC/OLE, базы данных и сетевые классы)
Это будет строить закрытой версии MFC DLL в каталог MFC SRC с стандартными именами MFCxx.DLL и MFCxxD.DLL. Необходимо будет скопировать их в соответствующее место на вашем пути для использования новой библиотеки DLL. MFCDLL.Мак makefile будет также восстановить библиотек импорта (MFCxx.LIB и MFCxxD.LIB) и поместите их в стандартный каталог MFC LIB. Это заменит готовые библиотеки MFCxx.LIB и MFCxxD.LIB, так что будьте внимательны.
Если вы хотите распространять модифицированную версию библиотеки MFC DLL, пожалуйста обязательно измените имя DLL-библиотеки в MFCDLL.Мак makefile и два.DEF-файлов. Смотрите makefile MFCDLL.Мак для получения дополнительной информации.
Вы можете изменять библиотеку и распространять розничной (/ release) изменение библиотеки только если вы переименовать его в нечто иное, чем MFCxx.DLL. Вы не может распространять отладочной версии либо встроенных или пользовательских построен отладки DLL.
Эти перераспределения ограничения являются прежде всего во избежание распространения нестандартных и потенциально вирус, содержащие DLL. в идеале следует не требуется восстановить файлы DLL и если вы повторно распространяете приложение с предварительно подготовленный MFCxx.DLL с продуктом Visual C++, вам не много проблем для вас и ваших пользователей.
Управление памятью
Приложение, использующее MFCxx.DLL использует общий распределитель памяти, представленной MSVCRTxx.DLL, Общие DLL C времени выполнения. Приложение, любые библиотеки DLL расширения, а также библиотеки DLL MFC, используйте этот распределитель общей памяти. С помощью общей библиотеке DLL для выделения памяти, библиотек DLL MFC можно выделить память, которая позднее освобождены приложением или наоборот. Поскольку приложение и DLL необходимо использовать же распределителя, не должны переопределять C++ глобального оператора new или удалить оператор. Те же правила применяются к остальной части процедур выделения памяти c времени выполнения (таких как malloc, realloc, бесплатно, и т.д.).
Порядковые числительные и класса __declspec(dllexport) и именования DLL
Мы не используем class функциональность __declspec(dllexport) компилятора C++. Вместо этого список экспорта входит в класс библиотеки источников (MFCxx.DEF и MFCxxD.DEF). Экспортируются только эти выбор набора точек входа (функции и данные). Другие символы, такие как частные реализации функции MFC или классов, не экспортируются сделали всего экспорта по порядковому номеру, без имени строки в таблице имя резидента или нерезидента .
С помощью class __declspec(dllexport) может быть жизнеспособной альтернативой для построения небольших DLL, но в случае большого DLL как MFC по умолчанию экспорт механизм имеет эффективность и способность ограничения .
То, что это все означает является что мы можем упаковать большое количество функций в релизе MFCxx.DLL, только около 800 Кбайт без ущерба для много исполнения или скорость загрузки. MFCxx.DLL были бы 100 K больше этот метод не используется.Это также позволяет добавить дополнительные записи точки в конце.DEF файл простое управление версиями без ущерба для эффективности скорость и размер экспорта по порядковому номеру. Изменения основной версии в библиотеке классов MFC изменит имя библиотеки. То есть, MFC30.Библиотека DLL — свободно распространяемый DLL, содержащих версии 3.0 библиотеки классов MFC. Обновление данной библиотеки DLL, скажем, в гипотетической 3.1 MFC, библиотека DLL будет иметь имя MFC31.DLL вместо этого. Опять же если изменить исходный код MFC для создания настраиваемой версии библиотеки DLL MFC, пожалуйста, используйте другое имя (и желательно без «MFC») в названии.
Технические примечания по номеру |nbsp; Технические примечания по категориям