Общие правила и ограничения
Только для систем Microsoft
При объявлении функции или объект без dllimport OR dllexport атрибут, функция или объект не считаются частью интерфейса библиотеки DLL.Таким образом, определение функции или объекта должно присутствовать в этом модуле или в другом модуле одной программы.Чтобы выполнить функцию или часть объекта интерфейса библиотеки DLL, необходимо объявить определение функции или объекта в другом модуле как dllexport.В противном случае формируется ошибка компоновщика.
При объявлении функции или объект с dllexport атрибут, ее определение должен появляться в какой-либо модуль одной программы.В противном случае формируется ошибка компоновщика.
Если один модуль в программе, содержащий оба dllimport и dllexport объявления для одной и той же функции или объекта dllexport атрибут имеет приоритет над dllimport атрибут.Однако предупреждение компилятора создается.Примеры.
__declspec( dllimport ) int i; __declspec( dllexport ) int i; // Warning; inconsistent; // dllexport takes precedence.
В C++ можно инициализировать глобально объявленный статический или локальный указатель данных или с адресом объекта данных, объявленного с dllimport атрибут, который формирует ошибку в c#.Кроме того, можно инициализировать статической локальной функции с адресом указателя функции, объявленной с dllimport атрибут.В c#, то назначение задает указатель на адрес преобразователя импорта библиотек DLL (заглушки кода, управление переключений функции), а не на адрес функции.В C++, он устанавливает указатель на адрес функции.Примеры.
__declspec( dllimport ) void func1( void ); __declspec( dllimport ) int i; int *pi = &i; // Error in C static void ( *pf )( void ) = &func1; // Address of thunk in C, // function in C++ void func2() { static int *pi = &i; // Error in C static void ( *pf )( void ) = &func1; // Address of thunk in C, // function in C++ }
Однако поскольку программа, которая включает dllexport атрибут в объявлении объекта должен предоставить определение для этого объекта в программе можно инициализировать global или local статический указатель функции с адресом a dllexport функция.Аналогично можно инициализировать global или local указатель статических данных с адресом a dllexport объект данных.Например, следующий код не создаются ошибки в c# или C++:
__declspec( dllexport ) void func1( void ); __declspec( dllexport ) int i; int *pi = &i; // Okay static void ( *pf )( void ) = &func1; // Okay void func2() { static int *pi = &i; // Okay static void ( *pf )( void ) = &func1; // Okay }
Из-за изменений в расширениях функциональности вставьте в Visual C++ .NET для создания приложения dllexport обычный последовательный между классами и специализациями шаблонов класса, если необходимо применить dllexport в обычный класс, имеющий базовый класс, который не помечен как dllexportкомпилятор создаст C4275.
Компилятор выдает предупреждение, если один и тот же базовый класс специализация шаблона класса.Чтобы избежать этого, следует помечать базовый класс с dllexport.Проблема с специализацией шаблона класса, в котором установки __declspec(dllexport); не допускаются для пометки шаблона класса.Вместо этого необходимо явно создать экземпляр шаблона класса и помечает данный экземпляр с explicit dllexport.Примеры.
template class __declspec(dllexport) B<int>; class __declspec(dllexport) D : public B<int> { // ...
Это решение не выполняется, если аргумент шаблона производный класс.Примеры.
class __declspec(dllexport) D : public B<D> { // ...
Поскольку это общий шаблон с шаблонами, компилятор был изменен семантика dllexport при применении к классу, который содержит один или более базовых классов и, если один или несколько из базовых классов специализация шаблона класса.В этом случае компилятор неявно применяется dllexport в специализациям шаблонов класса.В Visual C++ .NET, пользователь может выполнить следующие действия и получать предупреждение:
class __declspec(dllexport) D : public B<D> { // ...