这已经在很多地方进行了部分讨论,但对我来说仍然不起作用。
我有一个从delphi源代码编译的dll,它以两个名称导出一个函数,使用检查dll
>> dumpbin /EXPORTS MyLibrary.dll
我得到以下输出:
...
17 3 00070A88 MyFunction
...
46 24 00070A88 _MyFunction@48
...
所以我创建了一个名为 MyLibrary.def 的文件,其中包含以下内容:
EXPORTS
MyFunction
_MyFunction@48
并使用生成导入库
>> lib /def:MyLibrary.def /OUT:MyLibrary.lib /MACHINE:x86
使用 dumpbin 检查新的 lib 文件,我看到以下内容:
...
_MyFunction
...
__MyFunction@48
...
不知何故,lib 应用程序在函数名称前面添加了一个下划线。 (为什么?)
然后我尝试在 C++ 程序中使用此函数,使用 Microsoft Visual Studio C++ 2010 Express 进行编译(使用 lib 文件):
// MyLibrary.h
# define DllImport(Type) __declspec (dllimport) Type __stdcall
extern "C" DllImport(void)MyFunction(...);
// main.cpp
#import "MyLibrary.h"
...
MyFunction(....);
...
据我所知,现在应该可以工作,但我收到以下链接器错误:
... error LNK2001: Unresolved external sympol "__imp__MyFunction@48".
我不明白为什么会出错(我真的不明白整个事情是如何工作的......),但我又尝试了两件事。
- 将 MyLibrary.h 和 main.h 中的函数从 MyFunction 重命名为 _MyFunction
- 结果:有效!但为什么?我不想依赖这个,因为显然有些问题。
- 将我的函数重命名回 MyFunction 并删除 def-File 中的下划线,再次生成 lib 文件并尝试编译
- 结果:编译成功,但是启动程序时出现
MyApp - Entry Point Not Found
---------------------------
The procedure entry point MyFunction@48 could not be located
in the dynamic link library MyLibrary.dll.
我认为需要更深入地了解 lib 工具和链接器的内部工作原理,但到目前为止我找不到任何相关信息。
最佳答案
KB131313解释了您在尝试使用 lib
实用程序时会遇到的一个问题:
The only time you can use a .DEF file to create an import library from a .DLL for which you do not have the source code or object modules is if the .DLL exports functions via a C interface. Specifically, the functions need to have been declared to use the C calling convention.
您的函数使用 stdcall,而不是 cdecl,我们可以从函数名称中的 @
看出。不过,知识库文章解释了该怎么做:
按照 C++ 中的方式声明函数,但用于导出而不是导入。
大部分你已经做到了。您的调用约定是正确的,但末尾的
@48
意味着它需要有 48 个字节的参数。该函数期望将这些数据推送到堆栈上,并且在返回之前,该函数会将这些数据弹出。您在声明中使用...
与此不兼容。如果您不知 Prop 体的参数列表到底应该是什么,那么就继续定义 12 个
int
参数,这样至少堆栈结构是正确的。 (但是,如果您不知道该列表实际上应该是什么,那么您就已经很接近失败了。)用 C++ 编写一个虚拟实现。
实现可以为空。唯一的要求是代码可以编译和链接。
从该虚拟代码编译您自己的 MyLibrary.dll 版本。
确保它与原始 DLL 兼容。在其上运行
dumpbin
并查看它至少导出您在原始 DLL 中看到的函数名称的一个版本。 (您不需要两者;您的程序只会使用其中一个名称,并且如dumpbin
输出所示,两个名称都位于二进制文件中的同一位置,因此它不会无论您的程序最终使用哪个名称。)丢弃 DLL,只保留 LIB 文件。
- 使用lib文件链接真实的DLL。
如果链接器仍然提示找不到 __imp_MyFunction@48
,则从声明中删除 dllimport
部分。这应该删除 __imp_
前缀,使名称看起来更像 Delphi 名称。
如果所有其他方法都失败,您可以使用运行时动态链接而不是加载时。声明函数的指针类型,然后使用 LoadLibrary
和 GetProcAddress
来访问它。
关于c++ - 在C++中使用delphi库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12175301/