在工作中,我们正在使用的一个品牌的电池循环仪有一个专有的编码数据格式,我想直接读取我的脚本,而不是更大的ASCII版本的数据。制造商提供了一个DLL(没有库或头)连同一些 Delphi 示例代码一起使用,很少的文档和一个示例可执行文件(运行失败,错误为0xc 000007 b)。在this tutorial之后,我设法创建了一个.lib并将我的VS 2018项目链接到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,即失败并抛出异常。
运行时检查失败#0 -未在函数调用中正确保存ESP的值。这通常是由于调用了用一种调用约定声明的函数,而函数指针用另一种调用约定声明。
从文档中我知道使用了stdcall
。
文件中的其他相关信息:
函数打开数据文件(文件名:PChar):整数32;函数加载并获取下一时间数据(句柄:整数32; P时间数据:指针):整数32;程序关闭数据文件(句柄:整数32);
用OpenDataFile打开Maccor数据文件,返回一个句柄,如果句柄大于等于0,则文件打开成功。(...)由于读取整个数据文件是常见的,因此有一个双重用途函数LoadAndGetNextTimeData,加载时间数据并获取/返回最常用的数据。所有函数至少使用OpenDataFile返回的句柄。(...)若要读取数据,请一直调用LoadAndGetNextTimeData,直到它返回0。最后,必须使用CloseDataFile关闭文件以释放分配的内存。
当我将函数声明更改为
extern "C" int __stdcall OpenDataFile(const char*);
编译失败,出现2个错误代码:
LNK 1120 1未解决的外部问题
LNK 2019函数_main中引用了无法解析的外部符号_OpenDataFile@4
我知道这是由于C++名称损坏,但在这一点上我卡住了。
**Edit 1:**在not directly related question中找到一段开箱即用的代码:
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;
}
1条答案
按热度按时间vjrehmav1#
当我将函数声明更改为
编译失败,出现2个错误代码:
添加
__stdcall
是正确的做法。若要解决链接器错误,可以使用Visual Studio的
lib.exe
工具创建导入.lib
文件,该工具带有/DEF
选项,以指定一个.def
文件,该文件将编译器的修饰符号_OpenDataFile@4
Map到DLL实际导出的未修饰符号OpenDataFile
。请参见How To Create 32-bit Import Libraries Without .OBJs or Source或者,你可以使用MSVC的delay-loaded DLL特性。继续使用你已有的
.lib
文件,并在你的项目设置中将DLL标记为延迟加载。然后,在你的代码中,你可以使用一个延迟加载的通知钩子,使DLL函数在dliNotePreGetProcAddress
阶段使用未修饰的符号而不是修饰的符号导入。