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.
Related
I know it's not very good, but I need global variables across multiple files in my program. These are my graphics window's variables:
Name
Size
Status
.
I know I can make a .h file and declare all variables:
#pragma once
extern std::string GameName;
extern sf::RenderWindow Window;
extern std::string Status;
.
Then I want to define my variables in my main.cpp, so all files can access these values. But I cannot define these unless they are in the int main() loop. Is there another way, so I can define these variables not in main loop?
EDIT
Using Visual Studio 2017.
Errors:
LNK2001 unresolved external symbol "class sf::RenderWindow Window"
(?Window##3VRenderWindow#sf##A) Cubes
Library C:\Users\George\Documents\C++\Files\Libraries\Cubes
Library\Cubes Library\Cubes Library.obj 1
.
LNK2001 unresolved external symbol "class
std::basic_string,class
std::allocator > Status"
(?Status##3V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##A) Cubes
Library C:\Users\George\Documents\C++\Files\Libraries\Cubes
Library\Cubes Library\Cubes Library.obj 1
.
LNK1120 2 unresolved externals Cubes
Library C:\Users\George\Documents\C++\Files\Libraries\Cubes
Library\Debug\Cubes Library.dll 1
You can declare them in your main.cpp file, but in order to make them globally accessible, you have to define them outside your main function/loop. If you decalre them inside your main function/loop, they are local variables and cannot (easily) be accessed globally. Doing it this way combined with the header file you suggested will work.
// Global variables...
std::string GameName;
sf::RenderWindow Window;
std::string Status;
int main()
{
return 0;
}
You could also put them in another file, for example globals.cpp.
You would do it like this...
File: Main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#include <string>
extern std::string GameName;
//extern sf::RenderWindow Window;
extern std::string Status;
#endif
File: Main.cpp
#include "stdafx.h"
#include <iostream>
#include "Main.h"
std::string GameName;
//sf::RenderWindow Window;
std::string Status;
extern void foo(); // Function Prototype
int main()
{
GameName = "none";
Status = "none";
foo();
std::cout << GameName << " - " << Status << std::endl;
std::cout << "(HIT A KEY TO CONTINUE)" << std::endl;
getchar();
return 0;
}
File: Other.cpp
#include "stdafx.h"
#include "Main.h"
void foo()
{
// Global variables declared in Main.cpp are now accessible here
GameName = "Horizon New Dawn";
Status = "Finished";
}
This is how to do it using globals in a DLL.
// File: DLLGlobals.h
// This file is used in the DLL project
#ifndef __GLOBALS_H__
#define __GLOBALS_H__
#include <string>
extern "C"
{
extern __declspec(dllexport) std::string GameName;
extern __declspec(dllexport) std::string Status;
}
#endif//__GLOBALS_H__
// File: DLLGlobals.cpp
#include "stdafx.h"
#include "DLLGlobals.h"
extern "C"
{
// Define Global Variables (no C++ mangling)
__declspec(dllexport) std::string GameName = "Dishonored 2";
__declspec(dllexport) std::string Status = "Not Started";
}
// File: DLL.h
#ifndef __DLL_H__
#define __DLL_H__
// This file is included by code using the DLL project
#include <string>
extern "C"
{
__declspec(dllimport) std::string GameName;
__declspec(dllimport) std::string Status;
}
#endif//__DLL_H__
// File: Main.cpp
#include "stdafx.h"
#include <iostream>
#include "Main.h"
#include "<path_to_dll_header>\DLL.h"
int main()
{
std::cout << GameName << ": " << Status << std::endl;
std::cout << "(HIT A KEY TO CONTINUE)" << std::endl;
getchar();
return 0;
}
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;
}
I have the following code:
//mydll.cpp
#include <Windows.h>
#include <io.h>
#define STDOUT_FILEDESC 1
class MYSTDOUT {
bool shouldClose;
bool isBuffered;
public:
MYSTDOUT(bool buf = true, bool cl = true)
: isBuffered(buf),
shouldClose(cl)
{}
~MYSTDOUT() {
if (shouldClose) {
close(STDOUT_FILEDESC);
}
}
};
__declspec(dllexport) void* mydll_init_stdout()
{
static MYSTDOUT outs;
return &outs;
}
//test_dll.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <io.h>
typedef void* (__cdecl *MYPROC)(void);
int main(void)
{
int fd;
void *pstdout;
MYPROC init_stdout;
HMODULE handle = LoadLibrary(TEXT("mydll.dll"));
init_stdout = (MYPROC)GetProcAddress(handle,"mydll_init_stdout");//NULL
FreeLibrary((HMODULE) handle);
return 0;
}
I get that init_stdout is NULL.What could be a problem?
handle is OK(Not NULL)
Thank you
That is due to name-mangling.
You need to wrap the exported function in extern "C" as:
extern "C"
{
__declspec(dllexport) void* mydll_init_stdout()
{
static MYSTDOUT outs;
return &outs;
}
}
Have a check in Dependency Walker, or dumpbin /exports and you will see that mydll_init_stdout has been exported with a mangled C++ name. That's why the GetProcAddress call fails.
Use extern "C" to stop mangling.
extern "C"
{
__declspec(dllexport) void* mydll_init_stdout()
{
static MYSTDOUT outs;
return &outs;
}
}
I'm working on oop c++ with code::Blocks.
These are my first steps in oop because I program in C for microprocessors.
I'm having trouble linking a dll.
My the main from the dll project is:
#include "main.h"
#include "xclass.h"
// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)
{
MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// attach to process
// return FALSE to fail DLL load
break;
case DLL_PROCESS_DETACH:
// detach from process
break;
case DLL_THREAD_ATTACH:
// attach to thread
break;
case DLL_THREAD_DETACH:
// detach from thread
break;
}
return TRUE; // succesful
}
This is the header:
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
#include "xclass.h"
/* To use this exported function of dll, include this header
* in your project.
*/
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
void DLL_EXPORT SomeFunction(const LPCSTR sometext);
#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__
Basic stuff as you can see.
The problem is that I am including the class xclass with th main:
#include "xclass.h"
xclass::xclass()
{
//ctor
}
xclass::~xclass()
{
//dtor
}
and header
#ifndef XCLASS_H
#define XCLASS_H
class xclass
{
public:
xclass();
virtual ~xclass();
unsigned int GetCounter() { return m_Counter; }
void SetCounter(unsigned int val) { m_Counter = val; }
protected:
private:
unsigned int m_Counter;
};
#endif // XCLASS_H
I was able to link and use the dll in other project. A can even use the function in the DLL SomeFunction("teste x"); but I can not access and us the class:
#include <iostream>
#include "main.h"
//#include "../cvWrapper/main.h"
using namespace std;
int main()
{
xclass ClassInDll;// not working
SomeFunction("teste x"); //using the function in dll
printf("%d\n", 1);
return 0;
}
The build error is:
||=== testDLL, Debug ===| obj\Debug\main.o||In function main':|
C:\Users\SoftVision\Desktop\PrinterCode\DLL_test\testDLL\main.cpp|9|undefined
reference toxclass::xclass()'|
C:\Users\SoftVision\Desktop\PrinterCode\DLL_test\testDLL\main.cpp|14|undefined
reference to xclass::~xclass()'|
C:\Users\SoftVision\Desktop\PrinterCode\DLL_test\testDLL\main.cpp|14|undefined
reference toxclass::~xclass()'| ||=== Build finished: 3 errors, 0
warnings ===|
Thank for the help...
Actually you should export the class:
class DLL_EXPORT xclass
{
public:
xclass();
virtual ~xclass();
unsigned int GetCounter() { return m_Counter; }
void SetCounter(unsigned int val) { m_Counter = val; }
protected:
private:
unsigned int m_Counter;
};
Be careful when you export a class which is not a pure virtual class because you may meet some problems with a memory alignment. This happens because of different RTL versions in a different compilers. Instead export a pure virtual interface of you class.
class DLL_EXPORT IXClass
{
public:
IXClass();
virtual ~IXClass();
virtual unsigned int GetCounter()=0;
virtual void SetCounter(unsigned int val) =0;
};
Also avoid macros...
Good luck :).
You need to export the class too:
class DLL_EXPORT xclass {
//...
You might need to rearrange your headers a little - e.g. put the #define for DLL_EXPORT somewhere that can be included in both 'main.h' and 'xclass.h'.
http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL
I'm trying to create a C++ dynamic library that won't have a class. I'd like it to work similar to how you can include <string.h> and call strlen directly.
I can create a class that will compile, but won't link correctly with my library.
Here's the test library I'm working on now:
Header
#ifndef _DLL_H_
#define _DLL_H_
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
extern "C" __declspec(dllexport) int testMethod(int a);
#endif
Cpp
#include "dll.h"
int testMethod(int num)
{
std::cout << "test message" << std::endl;
return 1;
}
BOOL APIENTRY DllMain (HINSTANCE hInst, // Library instance handle. ,
DWORD reason, // Reason this function is being called. ,
LPVOID reserved) // Not used. )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
// Returns TRUE on success, FALSE on failure
return TRUE;
}
Finally, here's the class I'm using to test the Dll, which is told to link against the lib mingw outputs
#include <iostream>
#include "../Dll/dll.h"
using namespace std;
int main(int argc, char *argv[])
{
testMethod(5);
}
I haven't used C++ in about a year so I'm pretty rusty
extern "C" __declspec(dllexport) int testMethod(int a);
This needs to be dllimport in the application which is linking against the DLL. Most people compile their DLL with a #define which controls if it is an export or an import.
#ifdef INSIDE_MYDLL
#define MYDLLAPI __declspec(dllexport)
#else
#define MYDLLAPI __declspec(dllimport)
#endif
extern "C" MYDLLAPI int testMethod(int a);