c++ - 在C++中使用delphi库

标签 c++ delphi dll import

这已经在很多地方进行了部分讨论,但对我来说仍然不起作用。

我有一个从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".

我不明白为什么会出错(我真的不明白整个事情是如何工作的......),但我又尝试了两件事。

  1. 将 MyLibrary.h 和 main.h 中的函数从 MyFunction 重命名为 _MyFunction
    • 结果:有效!但为什么?我不想依赖这个,因为显然有些问题。
  2. 将我的函数重命名回 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,我们可以从函数名称中的 @ 看出。不过,知识库文章解释了该怎么做:

  1. 按照 C++ 中的方式声明函数,但用于导出而不是导入

    大部分你已经做到了。您的调用约定是正确的,但末尾的 @48 意味着它需要有 48 个字节的参数。该函数期望将这些数据推送到堆栈上,并且在返回之前,该函数会将这些数据弹出。您在声明中使用 ... 与此不兼容。

    如果您不知 Prop 体的参数列表到底应该是什么,那么就继续定义 12 个 int 参数,这样至少堆栈结构是正确的。 (但是,如果您不知道该列表实际上应该是什么,那么您就已经很接近失败了。)

  2. 用 C++ 编写一个虚拟实现。

    实现可以为空。唯一的要求是代码可以编译和链接。

  3. 从该虚拟代码编译您自己的 MyLibrary.dll 版本。

    确保它与原始 DLL 兼容。在其上运行 dumpbin 并查看它至少导出您在原始 DLL 中看到的函数名称的一个版本。 (您不需要两者;您的程序只会使用其中一个名称,并且如 dumpbin 输出所示,两个名称都位于二进制文件中的同一位置,因此它不会无论您的程序最终使用哪个名称。)

  4. 丢弃 DLL,只保留 LIB 文件。

  5. 使用lib文件链接真实的DLL。

如果链接器仍然提示找不到 __imp_MyFunction@48,则从声明中删除 dllimport 部分。这应该删除 __imp_ 前缀,使名称看起来更像 Delphi 名称。


如果所有其他方法都失败,您可以使用运行时动态链接而不是加载时。声明函数的指针类型,然后使用 LoadLibraryGetProcAddress 来访问它。

关于c++ - 在C++中使用delphi库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12175301/

相关文章:

c++ - 当迭代器不是随机访问时,如何在映射结束之前停止迭代 "n"?

c++ - 在 DNS 缓存中未找到 Libcurl 主机名

c++ - 如何以在Linux中编译后提供预处理的汇编文件和目标文件的方式编译c/cpp代码?

web-services - 将数据从 Delphi 客户端传递到 Web 服务/从 Web 服务传递数据

c++ - 捕获dll异常后访问冲突

c++ - 如何使用 Qt 在屏幕上绘制选择矩形?

delphi - 是否可以向 Delphi 的 TButtonedEdit 添加历史列表下拉列表?

delphi - 在同一台计算机上安装 Rad Studio 2007 和 Rad Studio 2010

java - 使用 x86javapath 的 x64 机器上的 x86java 上的 JNI 不满足链接错误

c# - 多项目 Visual Studio 解决方案无法调试一个项目 DLL