C++ DLL linker error - c++

I want to write a dll for an api of a device. since i am new to dlls i wanted to implement it on a simple text editor and then make one for the api.
I have made header file and cpp file but when i run the code i get error lnk2001 followed by lnk1120 which is unresolved external error.
I really have no idea where did i make a mistake, as far as i see i did it the right way. i was wondering if you guys could help me out. tnx.
here is my header file
// EditFuncsDll.h
#include <cstdio>
#include <vector>
#include <string>
namespace EditFuncs
{
class MyEditFuncs
{
private:
static std::vector<std::string> MyTextBox;
public:
static __declspec(dllexport) void Load(std::string command);
static __declspec(dllexport) void Save(std::string command);
static __declspec(dllexport) int Lines();
static __declspec(dllexport) void Add(std::string command);
static __declspec(dllexport) void Remove(std::string command);
static __declspec(dllexport) void Insert(std::string command);
static __declspec(dllexport) int wc(std::string command);
static __declspec(dllexport) void GetInfo();
};
}
and in my cpp file i just define the functions i declared in header file.
and these are the errors i get
Error 25 error LNK2001: unresolved external symbol "private: static class std::vector,class std::allocator >,class std::allocator,class std::allocator > > > EditFuncs::MyEditFuncs::MyTextBox" (?MyTextBox#MyEditFuncs#EditFuncs##0V?$vector#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##V?$allocator#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###2##std##A) C:\Users\Lucy\Desktop\Erfan\Text_Editor_DLL\Text_Editor_DLL\EditFuncsDll.obj Text_Editor_DLL
and
Error 26 error LNK1120: 1 unresolved externals C:\Users\Lucy\Desktop\Erfan\Text_Editor_DLL\Debug\Text_Editor_DLL.dll Text_Editor_DLL

The head of your cpp should be like this :
#include "EditFuncsDll.h"
#include <iostream>
#include <fstream>
using namespace std;
namespace EditFuncs
{
std::vector<std::string> EditFuncs::MyEditFuncs::MyTextBox;
void MyEditFuncs::Load(string command)
{
string filename; // The name of the file starts at the fifth character of the command and goes to the end
filename = command.substr(5,command.size());
ifstream inFile;
inFile.open(filename);
.
.
.

In your DLL's header file you may want to use a preprocessor macro, that expands to __declspec(dllimport) for DLL clients, and to __declspec(dllexport) for code that is implementing the DLL (i.e. your DLL .cpp files).
// EditFuncsDll.h
#ifdef EDIT_FUNCS_DLL_IMPLEMENTATION
#define EDIT_FUNCS_DLL __declspec(dllexport) // for DLL implementation
#else
#define EDIT_FUNCS_DLL __declspec(dllimport) // for clients
#endif
class EDIT_FUNCS_DLL MyEditFuncs
{
...
};
In your DLL's source .cpp file(s), you can #define EDIT_FUNCS_DLL_IMPLEMENTATION before #including your DLL header:
// EditFuncsDll.cpp
#define EDIT_FUNCS_DLL_IMPLEMENTATION
#include "EditFuncsDll.h"
// ... implementation code

Related

C++ DLL import class unresolved external symbol

Hi I'm sorry I've seen that there is a lot of "unresolved external symbol error" questions, and I've seen them but none of the answers that I found fixed my error.
I've tested 2 ways to compile the DLL and use the HelloWorld method from SerialPort class.
btw I'm using VS2019 community edition
Both ways are throwing the same error :
Error LNK2019 unresolved external symbol "public: void __thiscall SerialPort::HelloWorld(void)" (?HelloWorld#SerialPort##QAEXXZ) referenced in function _main Test DriverCore C:\Users\$USER\source\repos\Test DriverCore\Test DriverCore\Main.obj 1
To what I've understood it's a linker error and the name of the method that I'm using is unresolved (not found) but I have no idea how to fix that (I thought that extern "C" prevented this to happen)
I've also tried to add #pragma comment(lib, "DriverCore.lib")(with DriverCore.lib in the same Dir as DriverCore.h) but still nothing :/
Way 1
using a function to return a pointer to the class
DriverCore.h
#pragma once
#ifdef DRIVERCORE_EXPORTS
#define DLLCALL __declspec(dllexport)
#else
#define DLLCALL __declspec(dllimport)
#endif
class SerialPort
{
private:
bool connected = 0;
public:
SerialPort() {};
void HelloWorld();
bool isConnected() { return 0; };
int readSerialPort(char* buffer, unsigned int buf_size) { return 0; };
bool writeSerialPort(char* buffer, unsigned int buf_size) { return 0; };
};
extern "C" {
DLLCALL SerialPort* __stdcall CreateSerialPort();
};
DriverCore.cpp
#include "pch.h"
#include "DriverCore.h"
#include <iostream>
#define DRIVERCORE_EXPORTS
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
return TRUE;
}
SerialPort* __stdcall CreateSerialPort()
{
return new SerialPort();
}
void SerialPort::HelloWorld()
{
std::cout << "Hello World !";
}
Main.cpp
#include "pch.h"
#include <Windows.h>
#include <iostream>
#include "DriverCore.h"
typedef SerialPort* (__stdcall *SerialPortImported) ();
int main()
{
// instantiate the dll location
HINSTANCE hDLL = LoadLibraryW(L"DriverCore.dll");
if (!hDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
//Resolve Objects Addr
SerialPortImported pCSerialPort = (SerialPortImported) GetProcAddress(hDLL, "CreateSerialPort") ;
SerialPort* CSerialPort = pCSerialPort();
CSerialPort->HelloWorld();
return 0;
}
Way 2
without using extern "c" {...} but using __declspec directly onto the class declaration
DriverCore.h
#pragma once
#ifdef DRIVERCORE_EXPORTS
#define DLLCALL __declspec(dllexport)
#else
#define DLLCALL __declspec(dllimport)
#endif
class DLLCALL SerialPort
{
private:
bool connected = 0;
public:
SerialPort() {};
void HelloWorld();
bool isConnected() { return 0; };
int readSerialPort(char* buffer, unsigned int buf_size) { return 0; };
bool writeSerialPort(char* buffer, unsigned int buf_size) { return 0; };
};
DriverCore.cpp
#include "pch.h"
#include "DriverCore.h"
#include <iostream>
#define DRIVERCORE_EXPORTS
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
return TRUE;
}
void SerialPort::HelloWorld()
{
std::cout << "Hello World !";
}
Main.cpp
#include "pch.h"
#include <Windows.h>
#include <iostream>
#include "DriverCore.h"
int main()
{
// instantiate the dll location
HINSTANCE hDLL = LoadLibraryW(L"DriverCore.dll");
if (!hDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
//Resolve Objects Addr
SerialPort* pSerialPort = (SerialPort*) GetProcAddress(hDLL, "SerialPort") ;
pSerialPort->HelloWorld();
return 0;
}
Thanks a lot in advance for your help !
You are calling HelloWorld which is missing its implementation in your application.
There is some fundamental misunderstanding about how C++ executables are compiled and linked against DLLs.
No libraries:
All symbols that the Application needs must be defined in the Application.
All needed symbol definitions must be available to the linker.
Static libraries:
All symbols that the Application needs must be defined in the Application or a static library.
All needed symbol definitions must be available to the linker.
The symbols are added to the generated Application's executable.
Dynamic libraries:
All symbols that the Application needs must be defined in the Application or a dynamiclibrary.
All needed symbol definitions must be available to the linker.
The symbols remain at their original places and they are loaded only at load time. This allows swap the dynamic libraries with any other ABI-compatible one at load time.
Since you are not linking with the dll and only load it at runtime, the linker correctly complains about the missing HelloWorld method.
Extern "C" is irrelevant here.

How do I avoid `already defined` linking error with pugixml if two static libs contain pugixml objs?

So I have 2 static libs defined like this:
StaticLib1
// StaticLib1.h
#pragma once
class StaticLib1
{
public:
void doSomething1();
};
cpp:
// StaticLib1.cpp
#include "pugixml.hpp"
#include "StaticLib1.h"
void StaticLib1::doSomething1()
{
pugi::xml_node node;
}
StaticLib2
// StaticLib2.h
#pragma once
class StaticLib2
{
public:
void doSomething2();
};
cpp:
// StaticLib1.cpp
#include "pugixml.hpp"
#include "StaticLib2.h"
void StaticLib2::doSomething2()
{
pugi::xml_node node;
}
Main
#include <iostream>
#include "StaticLib1.h"
#include "StaticLib2.h"
int main(int argv, char** argc)
{
StaticLib1 staticlib1;
StaticLib2 staticlib2;
staticlib1.doSemething1();
staticlib2.doSemething2();
getchar();
return 0;
}
Now, if I build this. I get a lot of linking errors. Here are the first few linking errors:
3>StaticLib2.lib(StaticLib2.obj) : error LNK2005: "public: __thiscall pugi::xml_attribute::xml_attribute(struct pugi::xml_attribute_struct *)" (??0xml_attribute#pugi##QAE#PAUxml_attribute_struct#1##Z) already defined in StaticLib1.lib(StaticLib1.obj)
3>StaticLib2.lib(StaticLib2.obj) : error LNK2005: "public: __thiscall pugi::xml_attribute::xml_attribute(void)" (??0xml_attribute#pugi##QAE#XZ) already defined in StaticLib1.lib(StaticLib1.obj)
3>StaticLib2.lib(StaticLib2.obj) : error LNK2005: "private: __thiscall pugi::xml_attribute_iterator::xml_attribute_iterator(struct pugi::xml_attribute_struct *,struct pugi::xml_node_struct *)" (??0xml_attribute_iterator#pugi##AAE#PAUxml_attribute_struct#1#PAUxml_node_struct#1##Z) already defined in StaticLib1.lib(StaticLib1.obj)
...
...
Now, I understand that this linking error is because there is a pugixml.obj inside StaticLib1.lib, and there is pugixml.obj inside StaticLib2.lib. But I don't understand why this would cause linking error with pugixml signatures. Why would they be defined twice? If I call staticlib1.doSomething1() shouldn't main not care if there are multiple definitions of pugi? Shouldn't staticlib1.doSomething1() handle all of that?
on the pugiconfig.hpp I have these specific settings:
#ifndef HEADER_PUGICONFIG_HPP
#define HEADER_PUGICONFIG_HPP
#define PUGIXML_WCHAR_MODE
#define PUGIXML_HEAD_ONLY
#include "pugixml.cpp"
#endif
So yes, from user0042advice, I realize it is better to compile a pugixml.lib on your own rather than having #include "pugixml.cpp" on the config. I'm working with legacy code so these surprises are there. Now, I've fixed my issue and made my company code slightly cleaner.

Linker unresolved external symbol for inline function

I'm developing a C++ solution with Visual Studio 2015.
I have a cpp source file and header file hpp with this declaration.
Header:
#ifndef MyLib__FREEFUNCTIONS__INCLUDE__
#define MyLib__FREEFUNCTIONS__INCLUDE__
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
// Check if 'str' is null, empty or consists only of white-space characters.
inline bool IsNullOrWhiteSpace(string str);
// More functions
[ ... ]
#endif
And Source code:
#include "FreeFunctions.h"
inline bool IsNullOrWhiteSpace(string str)
{
return (str.empty() || (str.find_first_not_of(' ') == string::npos));
}
I use this function in a class:
#include "ConvertToOwnFormat.h"
#include "FreeFunctions.h"
ConvertToOwnFormat::ConvertToOwnFormat()
{
}
ConvertToOwnFormat::~ConvertToOwnFormat()
{
}
vector<Entry> ConvertToOwnFormat::ReadCatalogue(string path)
{
if (!IsNullOrWhiteSpace(path)
{
[ ... ]
}
}
And I get the following error in ConvertToOwnFormat::ReadCatalogue:
Error LNK2019 external symbol "bool __cdecl IsNullOrWhiteSpace(class
std::basic_string,class
std::allocator >)"
(?IsNullOrWhiteSpace##YA_NV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
unresolved referenced by the function "public: class std::vector > __cdecl
ConvertToOwnFormat::ReadCatalogue(class std::basic_string,class std::allocator >)"
(?ReadCatalogue#ConvertToOwnFormat##QEAA?AV?$vector#VEntry##V?$allocator#VEntry###std###std##V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##3##Z) MyProjectLib D:\Fuentes\Repos\MyProject\MyProjectLibConsoleTest\ConsoleMyProjectLib\Lib.lib(ConvertToOwnFormat.obj) 1
You have to put declaration of methods within the header. inline tells to compiler that it should replace call of function with the core of function. So, it need it at compilation time for every unit of compilation which use it
#ifndef MyLib__FREEFUNCTIONS__INCLUDE__
#define MyLib__FREEFUNCTIONS__INCLUDE__
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
// Check if 'str' is null, empty or consists only of white-space characters.
inline bool IsNullOrWhiteSpace(std::string str)
{
return (str.empty() || (str.find_first_not_of(' ') == std::string::npos));
}
// Others functions, prototype, ...
#endif
or remove inline in both source and header files
It's totally out of topic but never put a using namespace inside a header: a header should offer something but should not impose something like namespace. See also "using namespace" in c++ headers

error LNK2019: unresolved external symbol vs2013 [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 6 years ago.
I get this error, but I don't know how to fix it.
I'm using Visual Studio 2013.
code
-----DateUtils.h
#pragma once
#include <string>
class DateUtils
{
public:
DateUtils();
~DateUtils();
static time_t str2time_t(const std::string&, const std::string&);
};
-----ForexUtils32.h
#include <string>
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the FOREXUTILS32_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// FOREXUTILS32_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef FOREXUTILS32_EXPORTS
#define FOREXUTILS32_API __declspec(dllexport)
#else
#define FOREXUTILS32_API __declspec(dllimport)
#endif
// This class is exported from the ForexUtils32.dll
class FOREXUTILS32_API CForexUtils32 {
public:
CForexUtils32(void);
// TODO: add your methods here.
};
extern FOREXUTILS32_API int nForexUtils32;
FOREXUTILS32_API int fnForexUtils32(void);
/******************** Add Begin *************************/
FOREXUTILS32_API time_t str2time(const std::string&, const std::string&);
/******************** Add End *************************/
-------DateUtils.cpp
#include "stdafx.h"
#include "DateUtils.h"
#include <sstream>
#include <iomanip>
using namespace std;
DateUtils::DateUtils()
{
}
DateUtils::~DateUtils()
{
}
time_t str2time_t(const string& datetimeIn, const string& formatIn) {
struct tm tm_time;
// For C++11
istringstream iss(datetimeIn);
iss >> get_time(&tm_time, formatIn.c_str());
time_t time = mktime(&tm_time);
return time;
}
------ForexUtils32.cpp
// ForexUtils32.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "ForexUtils32.h"
#include "DateUtils.h"
// This is an example of an exported variable
FOREXUTILS32_API int nForexUtils32=0;
// This is an example of an exported function.
FOREXUTILS32_API int fnForexUtils32(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see ForexUtils32.h for the class definition
CForexUtils32::CForexUtils32()
{
return;
}
/******************** Add Begin *************************/
FOREXUTILS32_API time_t str2time(const std::string& datetime, const std::string& format)
{
time_t t = DateUtils::str2time_t(datetime, format);
return t;
}
/******************** Add End *************************/
Error message:
Error 1 error LNK2019: unresolved external symbol "public: static
__int64 __cdecl DateUtils::str2time_t(class std::basic_string,class
std::allocator > const &,class std::basic_string,class std::allocator > const &)"
(?str2time_t#DateUtils##SA_JABV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##0#Z) referenced in function "__int64 __cdecl str2time(class
std::basic_string,class
std::allocator > const &,class std::basic_string,class std::allocator > const &)"
(?str2time##YA_JABV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##0#Z) D:\visual
studio
2013\Projects\32bit\ForexUtils32\ForexUtils32\ForexUtils32.obj ForexUtils32
How can i fix this error ?Help me Please(I'm not good at english very much. Thanks)
The first line of the function definition
time_t str2time_t(const string& datetimeIn, const string& formatIn) {
have to be
time_t DateUtils::str2time_t(const string& datetimeIn, const string& formatIn) {
(Add the class name to which the member function belongs)

LNK2019 on a solution with a dll project

I am trying to create a solution which one project is the .exe and the other project is a simple dll. What i am trying to learn is how to link between two projects. I have searched stack-overflow and found really nice answers which I have followed, such as declaring the right header bath on:
Properties->Configuration Properties->C/C++->General->Additional Include Directories
Then setting the .lib on:
Properties->Configuration Properties->Linker->Input->Additional Dependencies
I used macros to generate that .lib file also. Here is the my simplified code:
The .exe:
cpp:
#include "stdafx.h"
#include "../ConsoleApplication2/HelloWorld.h"
int _tmain(int argc, _TCHAR* argv[])
{
hello_world hw;
hw.printHello();
getchar();
return 0;
}
The dll:
header:
#pragma once
#ifdef is_hello_world_dll
#define hello_world_exp __declspec(dllexport)
#else
#define hello_world_exp __declspec(dllimport)
#endif
class hello_world_exp hello_world
{
public:
hello_world();
~hello_world();
void printHello();
};
cpp:
#include "stdafx.h"
#include "HelloWorld.h"
#include <iostream>
hello_world::hello_world()
{
}
hello_world::~hello_world()
{
}
void printHello()
{
std::cout << "Hello World" << std::endl;
}
A note: The solution compiles fine when I don't call hw.printHello(); however when I do call it, the linker generates :
Error 1 error LNK2019: unresolved external symbol "__declspec(dllimport) public: void __thiscall hello_world::printHello(void)" (__imp_?printHello#hello_world##QAEXXZ) referenced in function _wmain C:\Users\usteinfeld\Desktop\Private\Students\Yana\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.obj ConsoleApplication1
This function is defined as a free function based on how you wrote it
void printHello()
It belongs to the class hello_world so you should scope it as such
void hello_world::printHello()
{
std::cout << "Hello World" << std::endl;
}