【问题标题】:How to create a 64-bit-DLL in Delphi 10.4 and call it from python/julia如何在 Delphi 10.4 中创建 64 位 DLL 并从 python/julia 调用它
【发布时间】:2021-08-16 12:15:42
【问题描述】:

我有一个 Delphi 库,我想将其编译为 DLL (PyMinMod_TRANS.dll),该库可以从 Python 或 Julia 等其他编程语言调用。从 RADStudio Delphi 10.4 编译到 Windows 32 位并通过 32 位 Python 2 调用它时

import ctypes as ct
PyMinMod_TRANS = ct.WinDLL('D:/Users/pjuergen/Dateien/git-repositories/remod-test/PyMinMod_TRANS.dll')

一切都按预期进行。

但是,如果我将它编译到 Windows 64 位并尝试从 64 位 Python 3(或 Julia)调用它,我会收到一条错误消息 WindowsError: [错误 126] 找不到指定的模块

我用 Dependency Walker 打开了PyMinMod_TRANS.dll,我发现很多缺失的依赖项,其中很多以API-MS-WINEXT-MS 开头,还有PYTHON27.DLLHVSIFILETRUST.DLLIESHIMS.DLL

Report from Dependency Walker

但是这并不能帮助我解决问题:)

我要编译的 Delphi 库使用包 System.SysUtilsPyAPImathclassesvcl.FileCtrl

我发现 PyAPI-File 来自这个来源:https://wiki.freepascal.org/Developing_Python_Modules_with_Pascal

换行

PythonLib = 'python27.dll';

PythonLib = 'python37.dll';

导致另一个错误 OSError: [WinError 127] 找不到指定的程序, 但是 Dependency Walker 的报告看起来几乎一样。

如何才能在 Python 3 和 Julia(64 位)中加载 DLL?

【问题讨论】:

  • 在 Python 和 Julia 中加载 Delphi DLL 没什么大不了的。只需创建一个 DLL 并编译它,确保使用 64 位目标。该问题可能与您的 DLL 的依赖关系有关,我们对此一无所知。 Dependency Walker 在现代 Windows 版本中不可靠。您需要调试自己的 DLL。我们不能那样做。
  • 你得到的错误WindowsError: [Error 126] The specified module could not be found是python代码还是DLL代码生成的?我猜是python代码。 DLL 可能不在您期望的位置。使用 ProcessMonitor 查看 python 尝试加载的内容以及获取的依赖项。如果错误来自 DLL 代码,则使用 Delphi 调试器调试 DLL。如果您不知道如何调试 DLL,请提出一个新问题。
  • 这个问题需要更多的关注。您是否有一个测试应用程序来验证 DLL 的功能?如果没有,请制作一个并测试您的 DLL 以确保它按预期工作。如果可行,那么您的 DLL 很好,这严格来说是 python/julia 的配置问题(即:DLL 的路径不正确)。如果 DLL 在测试应用程序中不起作用,那么这与 python/julia 无关 - 无论哪种方式,您都可以在提出问题之前缩小这个问题的范围。
  • 嗯,问题是“如何在 Delphi 中创建 64 位 DLL ...”。我有一个使用 Delphi-Code 的应用程序,它可以在 32 位和 64 位下工作。我还有一个 Python 2(32 位)应用程序,它加载 32 位 DLL 并按预期工作。问题是:如何让 Delphi/RADStudio 创建一个 64 位 DLL,它也可以按预期工作?作为 Python-Delphi-Interface,我使用的是此处发布的内容:wiki.freepascal.org/Developing_Python_Modules_with_Pascal 但是我无法弄清楚如何配置此 PyAPI 文件以创建适用于 python 3.7 的 64 位 DLL。
  • 但是现在 [Error 126] 不见了?这意味着 DLL 加载正常,而您只是试图调用 DLL 没有的导出名称。检查 Dependency Walker,可能在切换到 64 位时导出的名称会发生​​变化...

标签: python delphi dll


【解决方案1】:

模块初始化在 Python2 和 Python3 之间发生了一些变化,因此如果不调整初始化代码,仅将 DLL 交换为 Python3 是行不通的。在文档中有一个很好的article,其中包含一个包含棘手部分的代码示例,我猜这是这里的问题:

#if PY_MAJOR_VERSION >= 3
    PyObject *module = PyModule_Create(&moduledef);
#else
    PyObject *module = Py_InitModule("myextension", myextension_methods);
#endif

您链接到的PyAPI 代码使用Py_InitModule4_64,它在Python3 中(不再存在)。我猜这就是在运行时导致“找不到过程”错误的原因。

但也只是用另一个external PythonLib name 交换它是不行的,因为模块初始化系统的整个调用是不同的。所以我想如果没有实际修复这个 PyAPI 库以使用 Python3,那么你就不走运了。


AFAIU,即使它有效,您的软件堆栈也会如下所示:

Python =(ctypes 加载)=> Delphi DLL =(嵌入 Python C-API)=> Python

因此,Python 代码通过 ctypes 加载 DLL,它本身会调用 Python 嵌入系统以再次加载和启动 Python 解释器。很难说这是否可以毫无问题地工作,最后你说Python2可以做到。但从软件架构的角度来看,它似乎有点扭曲......

【讨论】:

  • 感谢您的回复。它还没有解决问题,但让我更好地理解了这个问题:) PyAPI 库的重点是,在将 DLL 重命名为 .pyd 后,我可以直接导入它并将 python-types 传递给 DLL,即我可以像使用任何 python 函数一样使用 DLL 中的 Delphi 函数,而无需在 python 中加载 ctypes。但也许我确实应该在不使用 PyAPI 而是从 Python 传递 ctypes 的情况下重写它。
猜你喜欢
  • 2011-12-21
  • 2021-11-17
  • 2015-03-19
  • 2013-06-08
  • 2011-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-19
相关资源
最近更新 更多