error LNK2019 in implementing a C++ class for DLL - c++

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?

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;
}
};

Related

Unresolved external symbol when using std::wstring

I declared the the following class:
#pragma once
#include <stdio.h>
#include <vector>
#include <string>
namespace util
{
class FileReader
{
public:
FileReader();
~FileReader();
bool open(const std::wstring& name);
void close();
bool read(std::vector<char>& buf, __int64 startFrom, int size);
__int64 size() const;
private:
FILE* m_file;
std::wstring m_name;
__int64 m_size;
};
}
And its implementation:
#include "FileReader.hpp"
namespace util
{
bool FileReader::open(const std::wstring& name)
{
if (!name.empty() && (m_name != name))
{
close();
if (_wfopen_s(&m_file, name.c_str(), L"rb") == 0)
{
m_name = name;
// Get the file size
_fseeki64(m_file, 0, SEEK_END);
m_size = _ftelli64(m_file);
rewind(m_file);
}
else
{
m_file = NULL;
}
}
return (m_file != NULL);
}
// ....
}
in a seperate library and use it like this:
FileTransfer.cpp
#include <util/FileReader.hpp>
// .....
if (!m_fileReader.open(m_localFileName)) // std::wstring m_localFileName;
{
::MessageBoxA(NULL, "Failed to open file", "Error", MB_ICONERROR);
stopFileTransmission();
return;
}
in another project. Both projects compile successfully, but the FileTransfer.obj fails to link:
Error 2 error LNK2019: unresolved external symbol "public: bool
__thiscall util::FileReader::open(class std::basic_string,class
std::allocator > const &)"
(?open#FileReader#util##QAE_NABV?$basic_string#GU?$char_traits#G#std##V?$allocator#G#2##std###Z)
referenced in function
__catch$?onRequestDirClicked#FileTransferWindow##AAEXXZ$0 C:\Users\x\Documents\dev\Server\FileTransfer.obj Server
I remember it was working when I used std::string, so I assume it has something todo with std::wstring.
Any idea what could be the issue?
It seems, the problem was that the two projects had different values for the setting
Treat wchar_t as built-in type
Setting it to No (/Zc:wchar_t-) for both projects, solved the linker error. I still don't really know what the consequences will be though.
try using extern "C" to declare the open function.

linking error with one function only LNK 2019

I have following class inside dll
header
class __declspec(dllexport) MyClass
{
public:
bool fun1(const CString& csFilename, int& nFileID );
bool fun2(int nFileID, int nImageNum, int nStartIndex);
};
cpp
bool MyClass::fun1(const CString& csFilename, int& nFileID )
{
}
bool Myclass::fun2(int nFileID, int nImageNum, int nStartIndex)
{
}
main
void main()
{
MyClass *p = new MyClass;
p->fun1(...); //if I comment this code compiles and builds
p->fun2(...); //this is ok
}
I am getting error LNK2019: unresolved external symbol "public: bool __thiscall...
only for fun1 not for fun2 even both are in same class why ?
thanks in advance.
I am not sure what is wrong here as it works after I replace CString with std string but I am not able to reproduce same error in another small example.
# admin I think this thread should be deleted as i am not able to reproduce it.

C++ How to set a private class member in a namespace within a static library?

Hi there fellow nerds,
i got a problem while tryin to code a static library. Im trying to set a private class member with a public class function. The class is located in a namespace. When i try to compile the example program (namespace_test) i get a LNK2001 Error stating a not resolved external symbol.
(Fehler 1 error LNK2001: Nicht aufgelöstes externes Symbol ""private: static bool ns_test::CTest::m_bPrivateMember" (?m_bPrivateMember#CTest#ns_test##0_NA)". ...\ns_test\namespace_test\namespace_test_api.lib(CTest.obj) namespace_test
)
How can i correctly implement that function?
Here is my code:
namespace_test_api.proj
namespace.h
namespace ns_test
{
class CTest
{
public:
CTest();
~CTest();
static void SetPrivateMember(bool i_bPrivateMember);
static bool bGetPrivateMember();
private:
static bool m_bPrivateMember;
};
}
CTest.cpp
#include "namespace.h"
namespace ns_test
{
CTest::CTest()
{
}
CTest::~CTest()
{
}
void CTest::SetPrivateMember(bool i_bPrivateMember)
{
CTest::m_bPrivateMember = i_bPrivateMember;
}
bool CTest::bGetPrivateMember()
{
return CTest::m_bPrivateMember;
}
}
namepsace_test.proj
namspace.h
namespace ns_test
{
class CTest
{
public:
CTest();
~CTest();
static void SetPrivateMember(bool i_bPrivateMember);
static bool bGetPrivateMember();
private:
static bool m_bPrivateMember;
};
}
main.cpp
#include <Windows.h>
#include <iostream>
#include "namespace.h"
#pragma comment (lib, "namespace_test_api.lib")
int main()
{
ns_test::CTest::SetPrivateMember(true);
std::cout << "PrivateMember: " << ns_test::CTest::bGetPrivateMember() << std::endl;
system("pause");
}
In CTest.cpp, you need to add the line:
bool ns_test::CTest::m_bPrivateMember;
This defines the static member, the entry in the class only declares it.
Note that the above will initialise it with false. You may want to make that explicit, or true:
bool ns_test::CTest::m_bPrivateMember = true;
Note this is an example of the One Definition Rule: you need to define each global exactly once.

What is the right way to return a reference to a class static data member? (I'm using Qt, in case it makes a difference)

I'm trying to get the address of a class static data member from a DLL and keep it around in host code. However, I'm loosing the pointer / reference to the member the minute I exit the method in the dll-manager which opens all the (Windows typedef) HINSTANCE s, even though I'm keeping them open.
My setup is:
A Qt GUI application, which includes a class that loads plugins from dlls. This dll-manager class doesn't use Qt stuff but for Qdir and Qstrings here and there...
The dll-manager should issue a bunch of LoadLibrary() calls to open DLLs and for each, call an exported function which returns the address of a static "info" struct inside the class the DLL exports.
For instance, The DLL class looks like this:
BlackNWhite.h
#ifdef BLACKNWHITE_EXPORTS
#define BLACKNWHITE_API __declspec(dllexport)
#else
#define BLACKNWHITE_API __declspec(dllimport)
#endif
// This class is exported from the BlackNWhite.dll
class BLACKNWHITE_API CBlackNWhite : PCOperatorBase
{
public:
CBlackNWhite(void);
virtual ~CBlackNWhite(void);
virtual int process(int* inBuffer, int* outBuffer, int bufferSize);
void getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters);
static const OperatorInfo& info();
protected:
static OperatorInfo operatorInfo;
};
extern "C" __declspec(dllexport) PCOperatorBase* getOperatorInstance();
extern "C" __declspec(dllexport) const PCOperatorBase::OperatorInfo& getOperatorInfo();
BlackNWhite.cpp
#include "stdafx.h"
#include "BlackNWhite.h"
PCOperatorBase::OperatorInfo CBlackNWhite::operatorInfo = {L"Black N White", L"modifier", L"color"};
const PCOperatorBase::OperatorInfo& CBlackNWhite::info()
{
return CBlackNWhite::operatorInfo;
}
extern "C" __declspec(dllexport) PCOperatorBase* getOperatorInstance()
{
return (PCOperatorBase*)(new CBlackNWhite());
}
extern "C" __declspec(dllexport) const PCOperatorBase::OperatorInfo& getOperatorInfo()
{
return CBlackNWhite::info();
}
CBlackNWhite::CBlackNWhite()
: PCOperatorBase()
{
ParameterDescriptor newParameter;
newParameter.label = L"Parameter 1";
parameters.push_back(newParameter);
}
CBlackNWhite::~CBlackNWhite()
{
}
int CBlackNWhite::process(int* inBuffer, int* outBuffer, int bufferSize)
{
while(bufferSize--)
*outBuffer++ = *inBuffer++;
return 0;
}
void CBlackNWhite::getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters)
{
outParameters = &parameters;
}
And this class inherits from a base class:
PCOperatorBase.h
#pragma once
#include "PCOperatorParameters.h"
#include <vector>
class PCOperatorBase
{
public:
typedef struct OperatorInfo
{
wchar_t* name;
wchar_t* type;
wchar_t* subtype;
} OperatorInfo;
PCOperatorBase(void){};
virtual ~PCOperatorBase(void){};
virtual void getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters) = 0;
virtual int process(int* inBuffer, int* outBuffer, int bufferSize) = 0;
protected:
std::vector<ParameterDescriptor>parameters;
};
And the DLL-manager has two relevant methods. One builds the list of available plugins and the other one just returns the string names of the plugins.
void PCOperatorManager::buildOperatorList(const QString path)
{
QDir operatorDirectory(QDir::currentPath() + path);
if(operatorList.size())
operatorList.clear();
QStringList operatorNameList = operatorDirectory.entryList(QStringList("*.dll"));
typedef PCOperatorBase::OperatorInfo*(*PCOClassInfoFunction)();
for(QStringList::iterator PCOClassName = operatorNameList.begin();
PCOClassName != operatorNameList.end();
PCOClassName++)
{
HINSTANCE PCOClassHandle;
if((PCOClassHandle = LoadLibrary((operatorDirectory.absolutePath() + "/"+ *PCOClassName).toStdWString().c_str())))
{
OperatorDescriptor newPCOClassDescriptor;
newPCOClassDescriptor.handle = PCOClassHandle;
newPCOClassDescriptor.info = (*((PCOClassInfoFunction)GetProcAddress(PCOClassHandle, "getOperatorInfo")))();
operatorList.push_back(newPCOClassDescriptor);
printf("\n we have: %ls", operatorList[0].info->name);
}
}
}
QStringList PCOperatorManager::getOperatorNameList()
{
QStringList operatorNameList;
printf("\n the list length is: %i", operatorList.size());
for(int i = 0; i < operatorList.size(); i++)
printf("\n we have again: %ls", operatorList[0].info->name);
//operatorNameList << QString::fromWCharArray((*PCOClass).info.name);
return operatorNameList;
}
What's happening is: inside buildOperatorList() I can access the static member of the DLL-class and assign it to the info member in the OperatorDescriptor struct. That is, the "test" printf statement that reads "we have" does print out the right value for that field.
However, inside getOperatorNameList() the info member is not valid anymore.
My line of thought is that what I'm doing is:
I have a pointer to a OperatorInfo struct, called info.
I get the address of a static OperatorInfo struct in the DLL-class,
called operatorInfo.
I assign the address of the class' operatorInfo to the pointer
called info. That is info = &CBlackNWhite::operatorInfo;
At this point, the pointer should stay valid as long as I don't issue a FreeLibrary() on the DLL HINSTANCE
So what's going on?
I see here operatorList is not a member variable of PCOperatorManager once it is added and constructed as in buildOperatorList I think you should ave access in getOperatorNameList()

Define sorting method ( that use std::sort for sorting) of a templated class in dll and calling it from another project

Sorry for my bad English. I have 2 projects. Project 1 is a MFC dll that contains class CMyContainer, class CEmployee. Project 2 is my main project. In project 2, I created an instance of CMyContainer of type CEmployee. Now I want to sort the container but I got an error
"error LNK2019: unresolved external symbol "bool __cdecl MyComparer(class CEmployee *,class CEmployee *)" (?MyComparer##YA_NPAVCEmployee##0#Z) referenced in function "public: void __thiscall CMyContainer<class CEmployee>::sortContainer(void)" (?sortContainer#?$CMyContainer#VCEmployee####QAEXXZ)"
How can I fix this problem?
// file MyContainer.h in project 1
#include <vector>
template <class T>
class _declspec(dllexport) CMyContainer
{
public:
CMyContainer(void);
~CMyContainer(void);
...
void sortContainer();
private:
std::vector<T*> items;
typename std::vector<T*>::iterator it;
};
template <class T> void CMyContainer<T>::sortContainer()
{
typedef bool (*comparer_t)(T*,T*);
comparer_t cmp = &MyComparer;
std::sort(items.begin(), items.end(), cmp);
}
//File Employee.h in project 1
#include "MyContainer.h"
class _declspec(dllexport) CEmployee
{
public:
CEmployee(void);
~CEmployee(void);
void setEmployeeCode(CString);
CString getEmployeeCode();
friend bool MyComparer(CEmployee*, CEmployee*);
private:
CString m_szEmployeeCode;
}
//File Employee.cpp in project 1
void CEmployee::setEmployeeCode(CString val){
m_szEmployeeCode= val;
}
CString CEmployee::getEmployeeCode(){
return m_szEmployeeCode;
}
bool MyComparer(CEmployee*pEmp1, CEmployee*pEmp2)
{
return (pEmp1->getEmployeeCode().Compare(pEmp2->getEmployeeCode())<0);
}
//File main.cpp in project 2
#include <..\Models\MyContainer.h>
#include <..\Models\Employee.h>
...
CMyContainer<CEmployee> *pListEmployee;
... // insert into pListEmployee
// sort pListEmployee
pListEmployee.sortContainer();//-> This command cause error
Try to export MyComparer from the .dll with _declspec(dllexport)