【问题标题】:Using delphi library in C++在 C++ 中使用 delphi 库
【发布时间】:2012-08-29 09:56:45
【问题描述】:

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

我有一个从 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 工具和链接器的内部工作有更深入的了解,但到目前为止我找不到任何相关信息。

【问题讨论】:

    标签: c++ delphi dll import


    【解决方案1】:

    KB131313 解释了尝试使用lib 实用程序时会遇到的一个问题:

    唯一可以使用 .DEF 文件从没有源代码或对象模块的 .DLL 创建导入库的情况是 .DLL 通过 C 接口导出函数。具体来说,需要声明函数以使用 C 调用约定。

    您的函数使用stdcall,而不是cdecl,我们可以从函数名称中的@ 看出。不过,知识库文章解释了该怎么做:

    1. 像在 C++ 中一样声明该函数,但为 export 而不是 import

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

      如果你不知道具体的参数列表到底应该是什么,那么继续定义 12 个int 参数,这样至少堆栈结构是正确的。 (但如果你不知道该列表到底应该是什么,那么无论如何你都快要完蛋了。)

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

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

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

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

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

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

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


    如果一切都失败了,您可以使用运行时动态链接而不是加载时。为函数声明一个指针类型,然后使用LoadLibraryGetProcAddress 来访问它。

    【讨论】:

    • +1 这太棒了。我们的产品附带一个用 Delphi 编写的 DLL。我们的许多客户都想从 C++ 中调用它,因此需要一个 .lib 文件。我们手动创建 .h 文件,然后使用 perl 脚本执行此答案中描述的阶段。这是最好的方法。
    • 我认为这就是 implib 的用途,@David。
    • 这是一个 Embarcadero 工具(如果我们指的是同一件事),因此会生成 Borland OMF 格式的 lib 文件。我不相信它会产生所有其他编译器供应商使用的 COFF 文件。还是最近发生了变化?无论如何,如果您认为 implib 是答案,那您为什么不在答案中提及呢?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多