Экспорт из библиотеки DLL с использованием DEF-файлов
DEF-файл определения модуля (*.def) — это текстовый файл, содержащий один или несколько операторов модуля, описывающих различные атрибуты библиотеки DLL. Если вы не используете ключевое слово __declspec(dllexport)
для экспорта функций библиотеки DLL, то для библиотеки DLL требуется DEF-файл.
Как минимум, DEF-файл должен содержать следующие операторы определения модуля:
Первым оператором в файле должен быть LIBRARY. Этот оператор определяет DEF-файл как принадлежащий библиотеке DLL. За оператором LIBRARY следует имя библиотеки DLL. Компоновщик помещает это имя в библиотеку импорта DLL.
Оператор EXPORTS перечисляет имена и, при необходимости, порядковые значения функций, экспортируемых библиотекой DLL. Вы назначаете функцию с порядковым номером, после которого следует имя функции со знаком @ и числом. При указании порядковых значений они должны находиться в диапазоне от 1 до N, где N — число функций, экспортируемых библиотекой DLL. Если требуется экспортировать функции по порядковому номеру, см. раздел Экспорт функций из библиотеки DLL по порядковому номеру, а не по имени в этом разделе.
Например, библиотека DLL, содержащая код для реализации дерева двоичного поиска, может выглядеть следующим образом:
LIBRARY BTREE
EXPORTS
Insert @1
Delete @2
Member @3
Min @4
При использовании мастера MFC DLL для создания библиотеки DLL MFC мастер создает скелет DEF-файла и автоматически добавляет его в проект. Добавьте в этот файл имена функций, подлежащих экспорту. Для библиотек DLL, отличных от MFC, создайте DEF-файл и добавьте его в проект. Затем выберите Проект>Свойства>Компоновщик>Ввод>Файл определения модуля и введите имя DEF файла. Повторите этот шаг для каждой конфигурации и платформы или сделайте это одновременно, выбрав Конфигурация = Все конфигурации и Платформа = Все платформы.
При экспорте функций в файл C++ необходимо либо поместить внутренние имена в DEF-файл, либо определить экспортированные функции с помощью стандартной компоновки C, используя модификатор extern "C". Если необходимо поместить внутренние имена в DEF-файл, их можно получить с помощью средства DUMPBIN или с помощью параметра /MAP компоновщика. Обратите внимание, что внутренние имена, создаваемые компилятором, зависят от компилятора. Если в DEF-файл помещаются внутренние имена, созданные компилятором Microsoft C++ (MSVC), то приложения, которые связаны с библиотекой DLL, также должны быть построены с использованием той же версии компилятора MSVC, чтобы внутренние имена в вызывающем приложении совпадали с экспортированными именами в DEF-файле библиотеки DLL.
Примечание.
Библиотека DLL, созданная с помощью Visual Studio 2015, может быть использована приложениями, созданными с помощью Visual Studio 2017 или Visual Studio 2019.
Если вы создаете расширение библиотеки DLL и экспортируете с помощью DEF-файла, поместите следующий код в начало и в конец файлов заголовков, содержащих экспортированные классы:
#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA
Эти строки гарантируют, что переменные MFC, которые используются внутри классов или добавляются в классы, экспортируются (или импортируются) из библиотеки DLL расширения MFC. Например, при создании производного класса с помощью DECLARE_DYNAMIC
макрос расширяется, добавляя в класс переменную элемента CRuntimeClass
. Если не указывать эти четыре строки, то библиотека DLL может скомпилироваться или скомпоноваться неправильно или вызывать ошибку, когда клиентское приложение связывается с библиотекой DLL.
При сборке библиотеки DLL компоновщик использует DEF-файл для создания файла экспорта (EXP) и файла библиотеки импорта (LIB). Затем компоновщик использует файл экспорта для создания файла DLL. Исполняемые файлы, которые неявно связываются с библиотекой DLL, компонуются с библиотекой импорта при их построении.
Обратите внимание, что MFC использует DEF-файлы для экспорта функций и классов из MFCx0.dll.