C++ DLL 导入 class 未解析的外部符号

C++ DLL import class unresolved external symbol

您好,很抱歉,我看到有很多“未解决的外部符号错误”问题,我也看到了,但是 none 我找到的答案修复了我的错误。

我已经测试了 2 种编译 DLL 和使用来自 SerialPort class 的 HelloWorld 方法的方法。 顺便说一句,我正在使用 VS2019 社区版

两种方式都抛出相同的错误:

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   

据我所知,这是一个链接器错误,我正在使用的方法的名称未解析(未找到),但我不知道如何解决(我认为 extern "C" 阻止了这会发生)

我也尝试添加 #pragma comment(lib, "DriverCore.lib")(DriverCore.lib 在与 DriverCore.h 相同的目录中)但仍然没有:/

方式一 使用函数 return 指向 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;
}

方式二 不使用 extern "c" {...} 而是直接在 class 声明中使用 __declspec

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

非常感谢您的帮助!

您正在调用 HelloWorld,它在您的应用程序中缺少实现。

对于 C++ 可执行文件是如何编译和链接到 DLL 的,存在一些根本性的误解。

没有图书馆:

  • 应用程序需要的所有符号都必须在应用程序中定义。
  • 链接器必须可以使用所有需要的符号定义。

静态库:

  • 应用程序需要的所有符号必须在应用程序或静态库中定义。
  • 链接器必须可以使用所有需要的符号定义。
  • 符号被添加到生成的应用程序的可执行文件中。

动态库:

  • 应用程序需要的所有符号必须在应用程序或动态库中定义。
  • 链接器必须可以使用所有需要的符号定义。
  • 符号保留在原来的位置,仅在加载时加载。这允许在加载时将动态库与任何其他 ABI 兼容的动态库交换。

由于您没有链接 dll 并且只在运行时加载它,链接器正确地抱怨缺少 HelloWorld 方法。

外部“C”与此处无关。