【问题标题】:C++ DLL import class unresolved external symbolC++ DLL 导入类未解析的外部符号
【发布时间】:2021-05-31 07:23:56
【问题描述】:

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

我已经测试了 2 种编译 DLL 和使用 SerialPort 类中的 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 在同一个目录中)但仍然没有:/

方式 1 使用函数返回指向类的指针

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

方式 2 不使用 extern "c" {...} 而是直接在类声明中使用 __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;
}

非常感谢您的帮助!

【问题讨论】:

  • 你需要在#include "DriverCore.h"之前定义DRIVERCORE_EXPORTS
  • @1201ProgramAlarm 是的,我已经更换了它,谢谢!但它并没有修复错误
  • 这应该可以工作,例如#2。
  • @drescherjm 我没有用第二种方法测试过,所以它将未解析的外部符号从public: void __thiscall SerialPort::HelloWorld(void)更改为__declspec(dllimport) public: void __thiscall SerialPort::HelloWorld(void)

标签: c++ class dll symbols


【解决方案1】:

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

对于如何编译 C++ 可执行文件并与 DLL 链接存在一些基本误解。

没有库:

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

静态库:

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

动态库:

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

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

外部“C”在这里无关紧要。

【讨论】:

  • 您好,感谢您的回答!在做class DLLCALL SerialPort {..} 时,我没有声明 SerialPort 类符号和他的所有方法吗?
  • @Rzdhop 声明 - 是的,所以编译器不会抱怨;定义 - 不,所以链接器确实抱怨。实际上,除了HelloWorld 之外,您正在内联定义所有这些。这就是为什么它是链接器抱怨的唯一方法的原因。
  • @Rzdhop "声明 SerialPort 类符号" 不存在这样的符号。 SerialPort 类型的导出 object 将具有相应的符号,SerialPort 的成员函数也将具有相应的符号。但是该类本身是一个编译时构造,而不是运行时构造,并且没有与之关联的“symbol”。这就是GetProcAddress(hDLL, "SerialPort") 将返回 NULL 的原因,顺便说一句,您应该在尝试使用该返回值之前在代码中检查它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
  • 2013-02-28
  • 2012-11-19
  • 1970-01-01
  • 2017-05-26
相关资源
最近更新 更多