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.
Related
1>game.obj : error LNK2001: unresolved external symbol "public: bool __cdecl GameStore::loadFromXml(void)" (?loadFromXml#GameStore##QEAA_NXZ)
1>protocolgame.obj : error LNK2001: unresolved external symbol "public: struct StoreCategory * __cdecl GameStore::getStoreCategoryByName(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?getStoreCategoryByName#GameStore##QEAAPEAUStoreCategory##AEBV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
1>C:\Users\Slavi Dodo\Documents\GitHub\forgottenserver\vc14\x64\Release\theforgottenserver.exe : fatal error LNK1120: 2 unresolved externals
I am so confused! I don't even understand why the error comes.
These is the declaration "gamestore.h"
#ifndef FS_GAMESTORE_H_ADCAA356C0DB44CEBA994A0D678EC92D
#define FS_GAMESTORE_H_ADCAA356C0DB44CEBA994A0D678EC92D
struct StoreOffer {
StoreOffer(uint32_t id, uint32_t thingId, uint8_t addon, uint32_t price, uint8_t type, uint8_t state, std::string name, std::string description, std::vector<std::string> icons)
: id(id), thingId(thingId), addon(addon), price(price), type(type), state(state), name(name), description(description), icons(icons) {}
uint32_t id;
uint32_t thingId;
uint32_t price;
uint8_t type;
uint8_t state;
uint8_t addon;
std::string name;
std::string description;
std::vector<std::string> icons;
};
struct StoreCategory
{
StoreCategory(std::string name, std::string description, std::vector<std::string> icons, std::vector<StoreOffer> offers)
: name(name), description(description), icons(icons), offers(offers) {}
std::string name;
std::string description;
std::string parentCategory;
std::vector<std::string> icons;
std::vector<StoreOffer> offers;
};
class GameStore
{
public:
bool reload();
bool loadFromXml();
StoreOffer* getStoreItemById(uint32_t id);
StoreCategory* getStoreCategoryByName(const std::string& name);
const std::vector<StoreCategory>& getStoreCategories() const {
return storeCategories;
}
bool enabled;
std::vector<StoreCategory> storeCategories;
};
#endif
And this is the definitions "gamestore.cpp"
#include "otpch.h"
#include "gamestore.h"
#include "pugicast.h"
#include "tools.h"
bool GameStore::reload()
{
storeCategories.clear();
return loadFromXml();
}
bool GameStore::loadFromXml()
{
return true;
}
StoreOffer* GameStore::getStoreItemById(uint32_t id) {
for (auto it : storeCategories) {
for (auto item : it.offers) {
if (item.id == id) {
return &item;
}
}
}
return nullptr;
}
StoreCategory* GameStore::getStoreCategoryByName(const std::string& name) {
auto it = std::find_if(storeCategories.begin(), storeCategories.end(), [name](StoreCategory& storeCategory) {
return storeCategory.name == name;
});
return it != storeCategories.end() ? &*it : nullptr;
}
I have read more about the error, but not even found a solution to my situation.
As you see the "loadFromXml" is just returning true, not accepting any arguments as well being public, the problem is very confusing!
Check if gamestore.cpp is being compiled or not!
If not add it to projectname.vcproj in CLCompile list.
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;
}
};
I am trying to follow the instructions on this site:
http://support.microsoft.com/kb/q168958
Here is the code:
#include <windows.h>
#include <malloc.h>
namespace Test {
template<class TYPE> class TestBuffer
{
private:
TYPE* m_pData;
size_t m_uSize;
public:
TestBuffer(size_t uSize) : m_pData(NULL), m_uSize(0)
{
m_pData = (TYPE*)malloc(uSize * sizeof(TYPE));
}
~TestBuffer() { if (NULL != m_pData) free(m_pData); }
public:
bool IsValid() const { return NULL != m_pData; }
operator TYPE*() const { return m_pData; }
};
template class __declspec(dllexport) Test::TestBuffer<wchar_t>;
__declspec(dllexport) bool GetCurrentDir(char* szDir, size_t uSize)
{
DWORD dwRequiredSize = ::GetCurrentDirectoryW(0, NULL);
Test::TestBuffer<wchar_t> wideCharBuffer(size_t(dwRequiredSize));
bool bResult = (dwRequiredSize - 1 ==
::GetCurrentDirectoryW(dwRequiredSize, (wchar_t*)wideCharBuffer));
wcstombs(szDir, (wchar_t*)wideCharBuffer, uSize);
return bResult;
}
} // namespace Test
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
char szPath[MAX_PATH] = { 0 };
Test::GetCurrentDir(szPath, MAX_PATH);
return TRUE;
}
Putting this in a WIN32 DLL project in VS spits out the following error:
error LNK2019: unresolved external symbol "class Test::TestBuffer<wchar_t> __cdecl wideCharBuffer(unsigned int)" (?wideCharBuffer##YA?AV?$TestBuffer#_W#Test##I#Z) referenced in function "bool __cdecl Test::GetCurrentDir(char *,unsigned int)"
I'm not sure why the linker can't find the definition as everything is defined right there, along with export statement for TestBuffer. Also, in the example, I shouldn't even need to export the explicit instantiation of TestBuffer as it isn't being exposed in the DLL interface, only GetCurrentDir() is.
Any guesses as to why the code isn't being generated for TestBuffer so the linker can find it?
P.S.
This is a contrived example to demonstrate the problem, not actual production code.
The compiler see the declaration of wideCharBuffer as a function declaration (most vexing parse). Try changing it to:
Test::TestBuffer<wchar_t> wideCharBuffer((size_t(dwRequiredSize)));
I have the following project files:
//connections.cpp
#include "stdafx.h"
#include "LibraryHeaders.h"
#include "FileManager.h"
#define WSAVersion 0x202
#define GSMsgID 0x100
extern HWND Main_hWnd;
bool InitConnections ()
{
FileManager::ConnectFile *connectfile = FileManager::ReadConnectFile(connectfile);
SockBase GSConnection(WSAVersion, TCP, connectfile->GS_IP, connectfile->GS_Port, Main_hWnd, GSMsgID);
if (GSConnection.Connect() != true) {return false;}
return true;
}
//FileManager.cpp
#include "stdafx.h"
#include "FileManager.h"
#include "LibraryHeaders.h"
using namespace FileManager;
ConnectFile* ReadConnectFile(ConnectFile *ConnectStruct)
{
FileLibrary connectfile("DMOConnection.cfg");
if (connectfile.OpenFile(HEAP, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, PAGE_READWRITE) != true) {return false;}
ConnectStruct->GS_IP = connectfile.parser->str_GetToken((char*)connectfile.FileBuff);
if (ConnectStruct->GS_IP == (const char*) -1) {return false;}
ConnectStruct->GS_Port = connectfile.parser->int_GetToken((char*)connectfile.FileBuff);
if (ConnectStruct->GS_Port == -1) {return false;}
return ConnectStruct;
}
//FileManager.h
namespace FileManager
{
struct ConnectFile
{
const char* GS_IP;
unsigned int GS_Port;
};
ConnectFile* ReadConnectFile(ConnectFile*);
}
And when trying to build the project i got this error:
Connections.obj : error LNK2019: unresolved external symbol "struct FileManager::ConnectFile * __cdecl FileManager::ReadConnectFile(struct FileManager::ConnectFile *)" (?ReadConnectFile#FileManager##YAPAUConnectFile#1#PAU21##Z) referenced in function "bool __cdecl InitConnections(void)" (?InitConnections##YA_NXZ)
I dont understand why, the linker should look up and see that ive defined FileManager::ReadConnectFile on FileManager.cpp but it doesnt, any tip how to fix this?
You're defining a free function:
ConnectFile* ReadConnectFile(ConnectFile *ConnectStruct)
not a member:
ConnectFile* FileManager::ReadConnectFile(ConnectFile *ConnectStruct)
Totally different.
Also:
using namespace FileManager;
and
error LNK2019: unresolved external symbol "struct FileManager::ConnectFile [...]
suggests you have a namespace FileManager and a struct FileManager... any reason for using the same name?
i fixed it by declaring the function out of the namespace:
namespace FileManager
{
struct ConnectFile
{
const char* GS_IP;
unsigned int GS_Port;
};
}
using namespace FileManager;
ConnectFile* ReadConnectFile(ConnectFile *ConnectStruct);
The IDE is VC11 Beta, thanks for the answers.
The code
using namespace FileManager;
ConnectFile* ReadConnectFile(ConnectFile *ConnectStruct)
{ ...some definition...}
defines the ReadConnectFile function not in the namespace FileManager, but in global namespace.
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)