在C++中调用Delphi编写的DLL:如何正确调用函数?
问题核心
调用约定不匹配导致ESP错误,添加__stdcall后链接报错是因为生成的.lib符号与编译器期望的修饰符号不匹配。以下是两种可行的解决方法:
解决方法一:修正静态链接的符号匹配
确认DLL导出的函数符号
打开对应项目平台(x86/x64)的VS命令提示符,运行命令查看DLL的导出符号:dumpbin /exports MacReadDataFile.dll记录输出中每个函数的名称和对应序号。
生成包含正确符号的.lib文件
创建MacReadDataFile.def文件,内容如下(替换序号为dumpbin输出的实际值):LIBRARY MacReadDataFile.dll EXPORTS OpenDataFile @1 LoadAndGetNextTimeData @2 CloseDataFile @3再通过lib工具重新生成库文件:
// 32位DLL lib /def:MacReadDataFile.def /out:MacReadDataFileLIB.lib /machine:x86 // 64位DLL lib /def:MacReadDataFile.def /out:MacReadDataFileLIB.lib /machine:x64修正代码中的函数声明
使用__stdcall调用约定声明函数,确保与DLL匹配:#pragma comment(lib, "MacReadDataFileLIB.lib") #include <string> extern "C" int __stdcall OpenDataFile(const char*); extern "C" int __stdcall LoadAndGetNextTimeData(int handle, void* timeData); extern "C" void __stdcall CloseDataFile(int handle); int main() { std::string path = "K:\\Testfile.036"; int handle = OpenDataFile(path.c_str()); if (handle >= 0) { // 需定义与Delphi一致的TimeData结构体,循环读取数据 // TimeData data; // while (LoadAndGetNextTimeData(handle, &data) != 0) { // // 处理数据 // } CloseDataFile(handle); } return 0; }重新编译链接即可解决错误。
解决方法二:动态调用DLL(更可靠,无需生成.lib)
直接通过LoadLibrary和GetProcAddress加载函数,避开静态链接的符号修饰问题:
#include <windows.h> #include <string> // 定义函数指针类型,严格匹配stdcall调用约定 typedef int (__stdcall* OpenDataFilePtr)(const char*); typedef int (__stdcall* LoadAndGetNextTimeDataPtr)(int, void*); typedef void (__stdcall* CloseDataFilePtr)(int); int main() { // 加载DLL,确保路径正确或DLL在程序运行目录下 HMODULE dllHandle = LoadLibraryA("MacReadDataFile.dll"); if (!dllHandle) { // 加载失败可通过GetLastError()查看错误码 return 1; } // 获取函数地址 OpenDataFilePtr openFile = reinterpret_cast<OpenDataFilePtr>(GetProcAddress(dllHandle, "OpenDataFile")); LoadAndGetNextTimeDataPtr loadNextData = reinterpret_cast<LoadAndGetNextTimeDataPtr>(GetProcAddress(dllHandle, "LoadAndGetNextTimeData")); CloseDataFilePtr closeFile = reinterpret_cast<CloseDataFilePtr>(GetProcAddress(dllHandle, "CloseDataFile")); if (!openFile || !loadNextData || !closeFile) { // 获取地址失败,清理资源 FreeLibrary(dllHandle); return 1; } // 调用函数打开文件 std::string filePath = "K:\\Testfile.036"; int fileHandle = openFile(filePath.c_str()); if (fileHandle >= 0) { // 定义与Delphi一致的TimeData结构体(需根据厂商文档补全) // 示例结构体: // typedef struct { // double timestamp; // double voltage; // double current; // int cycleNumber; // } TimeData; // TimeData currentData; // 循环读取所有数据 // while (loadNextData(fileHandle, ¤tData) != 0) { // // 处理读取到的数据 // } // 关闭文件 closeFile(fileHandle); } // 释放DLL资源 FreeLibrary(dllHandle); return 0; }
关键注意事项
- 平台匹配:VS项目的平台(x86/x64)必须与DLL完全一致,否则会出现
0xc000007b错误(示例exe无法运行也源于此)。 - 结构体匹配:
TimeData结构体需严格对应Delphi中的定义,包括成员类型、顺序和内存对齐方式,否则读取的数据会错乱。 - 调用约定:必须使用
__stdcall,这是Delphi函数的默认调用约定,不匹配会触发ESP错误。
内容的提问来源于stack exchange,提问作者JustSomeChemist
相关产品推荐
相关产品推荐

