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”与此处无关。
您好,很抱歉,我看到有很多“未解决的外部符号错误”问题,我也看到了,但是 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”与此处无关。