在c++中使用Delphi DLL -如何正确调用函数?



在工作中,我们使用的一个品牌的电池循环器有一个专有编码的数据格式,我想直接在我的脚本中读取,而不是更大的ASCII版本的数据。制造商提供了一个DLL(没有库或头)以及一些使用它的Delphi示例代码,很少的文档和一个示例可执行文件(错误0xc000007b无法运行)。遵循本教程,我设法创建了一个.lib并将我的VS2018项目链接到DLL。

使用以下代码,我可以从DLL中调用所需的函数之一:
#pragma comment(lib, "MacReadDataFileLIB.lib")
#include <string>
extern "C" int OpenDataFile(const char*);
int main()
{
std::string path = "K:\Testfile.036";
auto test = OpenDataFile(path.c_str());
}

当我遍历代码时,函数返回-1001,即失败并抛出异常。

Run-Time Check Failure #0 -在函数调用中ESP值没有被正确保存。这通常是调用用一种调用约定声明的函数和用不同调用约定声明的函数指针的结果。

从文档中我知道stdcall被使用。

文档中的其他相关信息:

function OpenDataFile(FileName: PChar): int32;函数LoadAndGetNextTimeData(Handle: int32;PTimeData:指针):int32;CloseDataFile(Handle: int32);

使用OpenDataFile打开Maccor数据文件并获得返回的句柄。如果句柄等于或大于0,则文件成功打开。(...(因为读取整个数据文件是很常见的,所以有一个双重用途的函数LoadAndGetNextTimeData来加载时间数据并获取/返回最常见的数据。所有函数都至少接受OpenDataFile返回的句柄。(...(要读取数据,只要它返回0,就一直调用LoadAndGetNextTimeData。最后,必须使用CloseDataFile关闭该文件以释放已分配的内存。

当我将函数声明改为

extern "C" int __stdcall OpenDataFile(const char*);

编译失败,有2个错误码:

LNK1120 1未解析的外部

LNK2019未解析的外部符号_OpenDataFile@4在函数_main中引用

我知道这是由于c++的名称混淆,但在这一点上我卡住了。

当我将函数声明更改为

extern "C" int __stdcall OpenDataFile(const char*);

编译失败,有2个错误码:

LNK1120 1 unresolved externals
LNK2019 unresolved external symbol _OpenDataFile@4 referenced in function _main

添加__stdcall是正确的做法。

要解决链接器错误,您可以使用Visual Studio的lib.exe工具创建一个导入.lib文件,并使用/DEF选项指定一个.def文件,该文件将编译器的修饰符号_OpenDataFile@4映射到DLL实际导出的未修饰符号OpenDataFile。参见如何创建不带. obs或源代码的32位导入库

或者,您可以使用MSVC的延迟加载DLL特性。继续使用您已经拥有的.lib文件,并在项目设置中将DLL标记为延迟加载。然后,在您的代码中,您可以使用延迟加载的通知钩子,以便在dliNotePreGetProcAddress阶段使用未修饰的符号而不是修饰的符号来导入DLL函数。

#include <string>
#include <cstring>
#include <delayimp.h>
#pragma comment(lib, "MacReadDataFileLIB.lib")
ExternC int __stdcall OpenDataFile(const char*);
FARPROC WINAPI myDelayLoadHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
if ((dliNotify == dliNotePreGetProcAddress) &&
(std::strcmp(pdli->szDll, "MacReadDataFileLIB.dll") == 0) &&
pdli->dlp.fImportByName &&
(std::strcmp(pdli->dlp.szProcName, "_OpenDataFile@4") == 0))
{
return (FARPROC) GetProcAddress(pdli->hmodCur, "OpenDataFile");
}
return NULL;
}
extern "C" const PfnDliHook __pfnDliNotifyHook2 = myDelayLoadHook;
int main()
{
std::string path = "K:\Testfile.036";
auto test = OpenDataFile(path.c_str());
}

我在一个不直接相关的问题中发现了一段代码:

typedef int(__stdcall* tMyFunction)(const char* filename);
int main(int argc, char* argv[]) {
std::string path = "K:\Testfile.036";
HINSTANCE m_dllHandle = LoadLibrary("MacReadDataFileLIB.dll");
tMyFunction function = (tMyFunction)GetProcAddress(m_dllHandle, "OpenDataFileASCII");
int value = function(path.c_str());
FreeLibrary(m_dllHandle);
m_dllHandle = NULL;
return 0;
}

最新更新