0

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 !

Rzdhop
  • 37
  • 9
  • Does this answer your question? [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – vasek Mar 01 '21 at 18:59
  • 4
    You need to define `DRIVERCORE_EXPORTS` before `#include "DriverCore.h"` – 1201ProgramAlarm Mar 01 '21 at 19:00
  • @1201ProgramAlarm Yes I've replaced it, thanks ! But it didn't fix the error – Rzdhop Mar 01 '21 at 19:58
  • This should have worked for example #2. – drescherjm Mar 01 '21 at 20:25
  • @drescherjm i haven't tested with the 2nd way,so it changes the unresolved external symbol from ```public: void __thiscall SerialPort::HelloWorld(void)```to ```__declspec(dllimport) public: void __thiscall SerialPort::HelloWorld(void) ``` – Rzdhop Mar 01 '21 at 20:33
  • That error is telling you to link to the import library in your test application. I don't use explicit linking with dlls so I am not sure I can help remove this dependency. – drescherjm Mar 01 '21 at 20:35
  • Related: [http://codeguru.com/cpp/w-p/dll/importexportissues/article.php/c123/Explicitly-Linking-to-Classes-in-DLLs.htm](http://codeguru.com/cpp/w-p/dll/importexportissues/article.php/c123/Explicitly-Linking-to-Classes-in-DLLs.htm) – drescherjm Mar 01 '21 at 20:44

1 Answers1

0

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.

Quimby
  • 17,735
  • 4
  • 35
  • 55
  • Hello and thanks for your answer ! While doing ```class DLLCALL SerialPort {..}``` am I not declaring the SerialPort class symbol and all his methods ? – Rzdhop Mar 01 '21 at 19:57
  • @Rzdhop Declaring - yes, so the compiler does not complain; defining - no, so the linker does complain. Actually you are defining all of them inline with the exception of `HelloWorld`. That is the reason why it is the only method the linker complains about. – Quimby Mar 01 '21 at 20:57
  • 1
    @Rzdhop "*declaring the SerialPort class symbol*" There exists no such symbol. An exported *object* of type `SerialPort` will have a corresponding symbol, and so will a member function of `SerialPort`. But the class itself is a compile-time construct, not a runtime one, and there is no "*symbol*" associated with it. That's why `GetProcAddress(hDLL, "SerialPort")` will return NULL, which btw you should check for in the code before attempting to use that return value. – dxiv Mar 01 '21 at 21:07