неразрешенный внешний символ для __declspec (dllimport) при использовании dll для экспорта класса

Я хочу определить производный класс на основе экспортированного класса dll. Базовый класс определен в проекте A, а производный класс - в проекте B.

Во-первых, в проекте A определен препроцессор MYDLL_BUILD. И я использую файл заголовка, чтобы указать экспорт / импорт:

    #if !defined(MYDLL_BUILD)
    #   pragma comment(lib, "myDll.lib")
    #endif

    #if defined(MYDLL_BUILD)
    #   define MYDLL_API __declspec(dllexport)
    #else
    #   define MYDLL_API __declspec(dllimport)
    #endif

Затем я определяю базовый класс:

class MYDLL_API DllObject
{
public:
    virtual ~DllObject() {}
protected:
    DllObject() { m_count = 3; }
private:
    int m_count;
};

В проекте B препроцессор MYDLL_BUILD не определен. Вот производный класс:

class MyClass : public DllObject
{
public:
    ~MyClass(){}
    MyClass() { m_data = 20; }
private:
    int m_data;
}; 

Я включил файлы dll и lib, но все равно получаю неразрешенную ошибку внешнего символа:

2>Test_Entry.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: virtual __thiscall ADAI::DllObject::~DllObject(void)" (__imp_??1DllObject@ADAI@@UAE@XZ) referenced in function "public: virtual __thiscall MyClass::~MyClass(void)" (??1MyClass@@UAE@XZ)
2>Test_Entry.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) protected: __thiscall ADAI::DllObject::DllObject(void)" (__imp_??0DllObject@ADAI@@IAE@XZ) referenced in function "public: __thiscall MyClass::MyClass(void)" (??0MyClass@@QAE@XZ)
2>c:\Users\Adai\Documents\Visual Studio 2010\Projects\Test_Main\Debug\Test_Main.exe : fatal error LNK1120: 2 unresolved externals

Я искал в Интернете, большинство ответов утверждают, что библиотека отсутствует. Но эти инструкции не решают мою проблему.

Когда я меняю

    class MYDLL_API DllObject

to

    class __declspec(dllexport) DllObject 

Решение компилируется без ошибок. Я действительно не понимаю причину. Может кто-нибудь помочь? Заранее спасибо.


person Chtoucas    schedule 17.03.2012    source источник
comment
Кажется, MYDLL_API не определяется в проекте A, как вы этого ожидали. Получите VS для создания предварительно обработанной версии файла, в котором определен DllObject (щелкните файл правой кнопкой мыши, перейдите в свойства, разверните C / C ++ и посмотрите параметры препроцессора). Убедитесь, что вывод содержит class __declspec(dllexport) DllObject, а не class __declspec(dllimport) DllObject   -  person Praetorian    schedule 17.03.2012
comment
Эти ошибки компоновщика не могут быть сгенерированы для опубликованного вами фрагмента кода. Вы написали код в заголовочном файле. Поэтому, когда вы #include его, нет никакой зависимости от библиотеки DLL .lib. В случае, если мы не смотрим на реальный код, это просто звучит так, как будто вы как-то неправильно #define MYDLL_BUILD.   -  person Hans Passant    schedule 17.03.2012
comment
Спасибо за ответ. У DllObject есть только файл заголовка, файла cpp нет. Я не могу создать предварительно обработанный файл для DllObject. Препроцессор MYDLL_BUILD определяется в свойствах проекта A. Коды, которые я вставил выше, являются реальными кодами, но это только часть, которая, как мне кажется, связана с сообщением об ошибке.   -  person Chtoucas    schedule 17.03.2012
comment
Обновление: я добавляю DllObject.cpp для создания предварительно обработанного файла. Вывод действительно содержит класс __declspec (dllexport) DllObject. Однако ошибки остались прежними. Я что-то упускаю?   -  person Chtoucas    schedule 17.03.2012
comment
Обновление: я добавляю функцию в DllObject.h и реализую ее в DllObject.cpp. Больше ничего не изменилось, настройки остались прежними. Затем он успешно компилируется. // DllObject.h MYDLL_API int foo (int n); класс MYDLL_API DllObject {общедоступный: виртуальный ~ DllObject () {} защищенный: DllObject () {m_count = 3; } частный: int m_count; }; // DllObject.cpp int foo (int n) {return 0; }   -  person Chtoucas    schedule 18.03.2012
comment
Я сталкиваюсь с той же проблемой и нажимаю на клавиатуру, не понимая, почему это происходит :(   -  person CygnusX1    schedule 05.08.2012
comment
@ CygnusX1 У меня тоже, в принципе, очень небольшая разница в оформлении. (Хотя для меня это больше тянущие за волосы, чем удары по клавиатуре)   -  person    schedule 24.10.2013
comment
Я тоже. В моем случае это было вызвано компиляцией библиотеки DLL с макросом UNICODE, а не исполняемыми файлами, которые связывались с ней.   -  person Mooing Duck    schedule 18.09.2014
comment
У меня была та же проблема: проект, который определял исходный класс, на самом деле ... не был построен. Это один из многих проектов, которые я редко меняю, поэтому он был выгружен. Некоторое время мне не удавалось установить соединение, потому что функция встроена.   -  person Liviu    schedule 23.11.2016


Ответы (2)


Причина в встраивании.

Короче говоря, чтобы сделать встроенные функции возможными, C ++ должен позволять включать и компилировать одно и то же определение функции в нескольких модулях компиляции (в основном в файлах .cpp), не вызывая ошибок. Компилятор может, но не должен выдавать код для любого из этих определений. Затем компоновщику разрешается выбрать одну копию.

Это усложняет создание dll, потому что вам нужно экспортировать ровно одну копию, но компилятор не знает, какая копия правильная. В этом случае, добавив некоторый код в DllObject.cpp, вы заставили компилятор выдавать код для DllObject, а у компоновщика была некоторая копия DllObject::~DllObject для экспорта.

Я не могу дать вам более подробное объяснение вашего конкретного случая, потому что я не знаю полного исходного кода и вариантов компиляции для вашего проекта.

person Tomek Szpakowicz    schedule 19.03.2012
comment
Значит, включения .h в модуль .cpp было недостаточно для его создания? Можно подумать, что генерация DLL может хотя бы отметить это как ошибку ... - person ; 24.10.2013

Сегодня у меня была такая же проблема. Я включал файлы .dll и .lib из своей версии DllObject, но это не помогло.

Чтобы исправить это, мне нужно было добавить имя .lib файлов к Properties->Linker->Input->Additional зависимостям проекта моей версии MyCLass.

Если это не сработает, вы можете добавить адрес каталога .lib местоположения в Properties->Linker->General->Additional каталоги библиотеки.

person Omkar Patil    schedule 31.03.2021