TN011. Использование MFC как часть библиотеки DLL

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

Интерфейсы DLL

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

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

Обычные библиотеки DLL MFC имеют несколько преимуществ:

  • Приложение, использующее библиотеку DLL, не должно использовать MFC и не должно быть приложением Visual C++.

  • При использовании обычных библиотек DLL MFC, которые статически связываются с MFC, размер библиотеки DLL зависит только от подпрограмм среды выполнения MFC и C, используемых и связанных.

  • При использовании обычных библиотек DLL MFC, которые динамически связываются с MFC, экономия памяти от использования общей версии MFC может быть значительной. Однако необходимо распространить общие библиотеки DLL, Mfc version.dll и Msvvcrt<version.dll>> с помощью библиотеки DLL.<

  • Проект DLL не зависит от того, как реализуются классы. Проект DLL экспортирует только нужные API. В результате, если реализация изменяется, обычные библиотеки DLL MFC по-прежнему действительны.

  • При использовании обычных библиотек DLL MFC, которые статически связываются с MFC, если библиотека DLL и приложение используют MFC, нет проблем с приложением, которое хочет другой версии MFC, чем библиотека DLL или наоборот. Так как библиотека MFC статически связана с каждой библиотекой DLL или EXE, нет никаких вопросов о какой версии у вас есть.

Ограничения API

Некоторые функции MFC не применяются к версии DLL из-за технических ограничений или из-за того, что эти службы обычно предоставляются приложением. С текущей версией MFC единственная функция, которая не применима CWinApp::SetDialogBkColor.

Создание библиотеки DLL

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

  • /D_WINDLL указывает, что компиляция для библиотеки DLL

  • /D_USRDLL указывает, что вы создаете обычную библиотеку DLL MFC

Необходимо также определить эти символы и использовать эти параметры компилятора при компиляции обычных библиотек DLL MFC, которые динамически связываются с MFC. Кроме того, необходимо определить символ _AFXDLL , и код БИБЛИОТЕКи DLL должен быть скомпилирован с помощью:

  • /D_AFXDLL указывает, что вы создаете обычную библиотеку DLL MFC, которая динамически связывается с MFC

Интерфейсы (API) между приложением и библиотекой DLL должны быть явно экспортированы. Мы рекомендуем определить интерфейсы для низкой пропускной способности и использовать только интерфейсы C, если это возможно. Интерфейсы Direct C проще поддерживать, чем более сложные классы C++.

Поместите API-интерфейсы в отдельный заголовок, который можно включить в файлы C и C++. См. заголовок ScreenCap.h в примере библиотеки DLLScreenCap mFC Advanced Concepts . Чтобы экспортировать функции, введите их в EXPORTS разделе файла определения модуля (). DEF) или включить __declspec(dllexport) в определения функций. Используется __declspec(dllimport) для импорта этих функций в исполняемый файл клиента.

Необходимо добавить макрос AFX_MANAGE_STATE в начале всех экспортированных функций в обычных библиотеках DLL MFC, которые динамически связываются с MFC. Этот макрос задает текущее состояние модуля для библиотеки DLL. Чтобы использовать этот макрос, добавьте следующую строку кода в начало функций, экспортированных из библиотеки DLL:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

WinMain —> DllMain

Библиотека MFC определяет стандартную точку входа Win32 DllMain , которая инициализирует производный объект CWinApp , как в обычном приложении MFC. Поместите все инициализацию библиотеки DLL в метод InitInstance , как в обычном приложении MFC.

Обратите внимание, что механизм CWinApp::Run не применяется к библиотеке DLL, так как приложение владеет основным насосом сообщений. Если библиотека DLL отображает бессерверные диалоговые окна или имеет собственное окно основного фрейма, основной насос сообщений приложения должен вызывать подпрограмму, экспортируемую библиотекой DLL, которая вызывает CWinApp::P reTranslateMessage.

См. пример DLLScreenCap для использования этой функции.

Функция DllMain , которую предоставляет MFC, вызовет метод CWinApp::ExitInstance класса, производный от CWinApp того, как библиотека DLL выгрузится.

Связывание библиотеки DLL

С помощью обычных библиотек DLL MFC, которые статически связываются с MFC, необходимо связать библиотеку DLL с Nafxcwd.lib или Nafxcw.lib и версией среды выполнения C с именем Libcmt.lib. Эти библиотеки предварительно созданы и могут быть установлены путем указания их при запуске программы установки Visual C++.

Пример кода

Полный пример программы DLLScreenCap см. в примере программы MFC Advanced Concepts. Ниже приведены некоторые интересные моменты, которые следует отметить в этом примере:

  • Флаги компилятора библиотеки DLL и приложения отличаются.

  • Линии ссылок и . ФАЙЛЫ DEF для библиотеки DLL и те, которые для приложения отличаются.

  • Приложение, использующее библиотеку DLL, не должно находиться в C++.

  • Интерфейс между приложением и библиотекой DLL — это API, доступный для использования C или C++ и экспортируемый с помощью DLLScreenCap.def.

В следующем примере показан API, определенный в обычной библиотеке DLL MFC, которая статически связывается с MFC. В этом примере объявление заключено в блок для пользователей extern "C" { } C++. Это имеет несколько преимуществ. Во-первых, это делает api DLL доступными для клиентских приложений, отличных от C++. Во-вторых, это снижает нагрузку на библиотеку DLL, так как к экспортируемой имени не применяется управление именами C++. Наконец, это упрощает явное добавление в объект. DEF-файл (для экспорта по порядковой версии) без необходимости беспокоиться о переключение имен.

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

struct TracerData
{
    BOOL bEnabled;
    UINT flags;
};

BOOL PromptTraceFlags(TracerData FAR* lpData);

#ifdef __cplusplus
}
#endif

Структуры, используемые API, не являются производными от классов MFC и определены в заголовке API. Это снижает сложность интерфейса между библиотекой DLL и приложением и делает библиотеку DLL для использования программами C.

См. также

Технические примечания по номеру
Технические примечания по категории