17
votes

I want to define a derived class based on a dll exported class. The base class is defined in Project A, and the derived class is in Project B.

Firstly, in Project A, preprocessor MYDLL_BUILD is defined. And I use a header file to specify export/import:

    #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

Then I define the base class:

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

In Project B, the preprocessor MYDLL_BUILD is not defined. Here is the derived class:

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

I have included the dll and lib file, but still I get the unresolved external symbol error:

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

I searched online, most of the answers claim that the lib is missing. But those instructions do not solve my problem.

When I change

    class MYDLL_API DllObject

to

    class __declspec(dllexport) DllObject 

The solution compiles with no error. I really do not understand the reason. Can someone please help? Thanks in advance.

2
Seems MYDLL_API is not being defined in Project A as you're expecting it to. Get VS to generate a preprocessed version of the file that DllObject is defined in (right click on the file, go to properties, expand C/C++ and look in the preprocessor options). Make sure the output contains class __declspec(dllexport) DllObject and not class __declspec(dllimport) DllObjectPraetorian
Update: I add a function in DllObject.h and implement it in DllObject.cpp. Nothing else has been changed, and the settings are the same as well. Then it compiles successfully. // DllObject.h MYDLL_API int foo(int n); class MYDLL_API DllObject { public: virtual ~DllObject() {} protected: DllObject() { m_count = 3; } private: int m_count; }; // DllObject.cpp int foo(int n) { return 0; }Chtoucas
I am facing exactly the same problem and hitting my keyboard not understanding why it is happening :(CygnusX1
@CygnusX1 Me too, basically, very slight difference in the decoration. (Although for me it's hair pulling more than keyboard hitting)user645280
I was too. In my case, it was caused by the DLL being compiled with the UNICODE macro, but not the executables that were linking with it.Mooing Duck

2 Answers

6
votes

The reason is inlining.

In short, to make inline functions possible C++ must allow the same definition of function to be included and compiled in multiple compilation units (basically .cpp files) without causing errors. Compiler can, but doesn't have to emit code for any of this definitions. Then linker is allowed to chose one copy.

This complicates dll creation because you need to export exactly one copy but compiler doesn't know which copy is the right one. In this case by adding some code to DllObject.cpp you made the compiler emit code for DllObject and linker had some copy of DllObject::~DllObject to export.

I cannot give you more detailed explanation of your particular case because I don't know full source and compilation options for your project.

1
votes

I had the same issue today. I was including the .dll and .lib files from my version of DllObject, But it wasn't helping.

To fix, What I had to do was add the .lib files name to my MyCLass version's project's Properties->Linker->Input->Additional dependencies.

If this doesn't work, You might want to add the .lib location's directory address in Properties->Linker->General->Additional library directories.