batuman
batuman

Reputation: 7304

error LNK2019 in implementing a C++ class for DLL

I implement a C++ class as DLL. But I have linker error when I interface to the dll. I have proper setup and not sure what is wrong. I researched, but can't find relevant solution, so I raise the query.

ASM_Lib.h

    #ifdef EXPORT
    #define DLLCLASS __declspec(dllexport)
    #else
    #define DLLCLASS __declspec(dllimport)
    #endif
    class ASM
    {
        public:
            ASM();
            ~ASM();
            int loadData(string path, string ext);
            int landmarkEqualization();

        private:
            vector<PtsData_<CurrentType_>> pts;//this vector size is same as number of images, released after use
            vector<string> files;//file names
            vector<TrainingData_<CurrentType_>> td;//this vector size is same as number of images, released after use
            vector<Mat> images;
    };

    extern "C" /*Important for avoiding Name decoration*/
    {
        DLLCLASS  ASM* _cdecl CreateASMObject();
    };

    // Function Pointer Declaration of CreateASMObject() [Entry Point Function]
    typedef ASM* (*CREATE_ASM) ();

ASM_Lib.cpp

namespace VIDEO_ANALYTICS_PLATFORM{

    DLLCLASS ASM* _cdecl CreateASMObject() {
        return new ASM();
    }

    ASM::ASM()
    {
    }

    ASM::~ASM()
    {
    }

    int ASM::loadData(string path, string ext)
    {

            return FILE_READ_WRITE_ERROR;
    }

    ///*
    //This loop equalize all landmark points to 
    //be equal distances
    //*/
    int ASM::landmarkEqualization()
    {
        //Clear vector
        pts.clear();
        vector<PtsData_<CurrentType_>>().swap(pts);
        return SUCCESS;
    }


}

Then in my test program, I interfaced as

#include "stdafx.h"
#include <iostream>
#include "ASM_Lib.h"
using namespace VIDEO_ANALYTICS_PLATFORM;

int _tmain(int argc, _TCHAR* argv[])
{
    HINSTANCE hDLL = LoadLibrary(L"ASM_Lib.dll"); 

    if (hDLL == NULL){
        std::cout << "Failed to load library.\n";
    }else{
        CREATE_ASM pEntryFunction = (CREATE_ASM)GetProcAddress(hDLL, "CreateASMObject");
        ASM* pASM = pEntryFunction();
        if (pASM) {                             
            pASM->loadData("C:\\PointsFiles", "pts");                         
        }
        FreeLibrary(hDLL);
    }

    std::cin.get();

    return 0;
}

But I have LNK2019 link error (referenced in function wmain) and I don't have wmain. What could be the problem?

test.obj : error LNK2019: unresolved external symbol "public: int __cdecl VIDEO_ANALYTICS_PLATFORM::ASM::loadData(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?loadData@ASM@VIDEO_ANALYTICS_PLATFORM@@QEAAHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@Z) referenced in function wmain

If I comment out this API pASM->loadData("C:\\PointsFiles", "pts");, then it works and can load the dll properly.

EDIT: Last update

ASM_Lib.h
#ifdef EXPORT
#define DLLCLASS __declspec(dllexport)
#else
#define DLLCLASS __declspec(dllimport)
#endif

namespace VIDEO_ANALYTICS_PLATFORM{

    class i_ASM
    {
       public:
          virtual ~i_ASM(){ ; };
          virtual int loadData(string path, string ext)=0;
          virtual int landmarkEqualization() = 0;
    };

    class ASM : public i_ASM
    {
        public:
            ASM(){ }
            int loadData(string path, string ext);
            int landmarkEqualization();

        private:
            vector<PtsData_<CurrentType_>> pts;//this vector size is same as number of images, released after use
            vector<string> files;//file names
            vector<TrainingData_<CurrentType_>> td;//this vector size is same as number of images, released after use
            vector<Mat> images;
    };

    extern "C" 
    {
        DLLCLASS  i_ASM* _cdecl CreateASMObject();
    };
}

ASM_Lib.cpp
namespace VIDEO_ANALYTICS_PLATFORM{

    DLLCLASS i_ASM* _cdecl CreateASMObject() {
        return new ASM();
    }   

    int ASM::loadData(string path, string ext)
    {
         return 0;
    }

    ///*
    //This loop equalize all landmark points to 
    //be equal distances
    //*/
    int ASM::landmarkEqualization()
    {
        //Clear vector
        pts.clear();
        vector<PtsData_<CurrentType_>>().swap(pts);
        return SUCCESS;
    }
}

Test.cpp
#include "ASM_Lib.h"
using namespace VIDEO_ANALYTICS_PLATFORM;

int _tmain(int argc, _TCHAR* argv[])
{       
     ASM* pASM = ::CreateASMObject();
     if (pASM) {
         pASM->loadData("C:\\PointsFiles", "pts");
         pASM->~ASM();
         pASM = NULL;
     }

    return 0;
}

I think, my last update should work. But still have linker error LNK2019 for both loadData() and ~ASM(). I did both test project and ASM_Lib project in the same solution. What could be wrong?

Upvotes: 1

Views: 271

Answers (1)

Nikerboker
Nikerboker

Reputation: 833

DLL exports only CreateASMObject function. ASM::loadData is not exported, but used in the test app. I can propose 2 ways to fix:

1) Attribure with __declspec(dllexport) the whole ASM class or loadData member only, and add ASM_Lib.lib to test app project.

2) Declare pure abstract class (interface) IASM and change the return type of CreateASMObject:

class IASM
{
public:
  virtual ~IASM() = 0;
  virtual int loadData(string path, string ext) = 0;
};

extern "C"
{
  DLLCLASS  IASM* _cdecl CreateASMObject();
};

Then derive ASM from IASM and implement abstact methods (it may be done inside CPP file). In this case linker does not need the address of loadData method, because it will be resolved in runtime via vtable.

PS. You must be sure that the DLL and its client use the same instance of heap manager (e.g. the same version of C runtime DLL). Otherwize it is unsafe to call delete for an object, created in another module. Solution is to add a method implementing deletion:

class IASM
{
public:
  virtual void destroy() = 0;
protected:
  ~IMyAPI() = default;
};    

class ASM: public IASM
{
public:
  virtual void destroy() override
  {
    delete this;
  }
};    

Upvotes: 2

Related Questions