Reputation: 7304
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
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