0
votes

I'm having a linking problem when compiling a class, derived from an interface from another DLL. This is the code. I have an c++ interface (abstract class), specified in DLL like this:

// ============================ Source DLL
// header IFace.h"
#ifdef MY_EXPORTS
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif

class MY_API IFace
{
public:
    virtual ~IFace() {};
    virtual bool Foo() = 0;
};

// ============================ My DLL
// header
#ifdef MY_EXPORTS22
#define MY_API22 __declspec(dllexport)
#else
#define MY_API22 __declspec(dllimport)
#endif

#include "IFace.h"

class MY_API22 MyClass_Mock : public IFace
{
// IFace
public:
virtual ~MyClass_Mock() {};
virtual bool Foo() ;
};

// cpp file
bool MyClass_Mock::Foo()
{
    return true;
}

When I compile my DLL, which implements the interface IFace, I get the linker error:

  • error LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl IFace::IFace(void)"
  • error LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl IFace::IFace(class IFace const &)"
  • error LNK2019: unresolved external symbol "__declspec(dllimport) public: class IFace & __cdecl IFace::operator=(class IFace const &)"
  • error LNK2001: unresolved external symbol "__declspec(dllimport) public: class IFace & __cdecl IFace::operator=(class IFace const &)"

When I explicitly define (or delete in C++11) copy ctor and assignment operator, I still have have errors for default ctor and dtor.

I don't want to link against .lib file for the source DLL as I want to load it dynamically later through LoadLibrary. How can I fix this linking problem?

2
Standard C++ doesn't allow you to declare a true interface that has no link dependencies. You'd have to use the non-standard MSVC++ __interface keyword instead. Added for this reason.Hans Passant
Thanks Hans. It works, but for project with defined macro WIN32_LEAN_AND_MEAN it gives a error "error C2504: 'IUnknown' : base class undefined" even though my small code snippet doesn't have anything from COM.Anton K
Hi Anton K, have you found any solution to this? I mean avoiding the need of the dll of IFace to compile MyClass_Mock. Thankslorenzolightsgdwarf

2 Answers

0
votes

Change class MY_API IFace for class IFace.

If you leave MY_API specified, Source DLL will not export IFace because it has no definition. By the other hand, My DLL will try to import IFace from the Source DLL, but it will fail because there is no exported definition of IFace.

If you remove MY_API, when My DLL tries to use IFace, the header file that declares it will suffice (i.e. IFace.h).

0
votes

Creating DLLs which export interface is a problematic area.

There is no standard ABI for C++ classes, and there is no guarantee that the class (which is code compatible) will be binary compatible with a different compiler.

On Windows there is a semi form of standard, where classes match COM objects, and can be considered to be compatible.

Memory management

On Windows malloc/free and new/delete are implemented in the runtime. This may be a shared runtime (e.g. msvcr120.dll), or compiled into the binary (.dll,.exe). If new is called in one runtime (static library) and delete in another, then a crash happens (different heaps called for free).

To avoid this, use a static constructor function to build your class, and give a virtual deletor, or use reference counting.

Avoid implementations

virtual ~IFace() {};

The above code creates code which is defined in the header file, which gets bound into the caller. If this code is ever incompatible with the implementation, then the wrong code may be called. To ensure that only the virtual interface is called, you need to limit the interface class to the visible functions, and no implementations.

class IFace {
  public:
    virtual Delete() = 0;
    virtual Method1() = 0;
...
};

IFace * MYAPI Constructor();

Implementation

class MY_API IFace
{
  public:
    virtual bool Foo() = 0;
    virtual void Delete() = 0;
};


IFace * MY_API22 MyConstructor()


class MY_API22 MyClass_Mock : public IFace
{
// IFace
public:
  virtual void Deletor() { delete this };
  virtual bool Foo() ;
};

// cpp file
bool MyClass_Mock::Foo()
{
    return true;
}
IFace * MyConstructor()
{
     return new MyClass_Mock;
}