【问题标题】:Load a DLL with dependencies in Python在 Python 中加载具有依赖项的 DLL
【发布时间】:2016-09-27 20:57:10
【问题描述】:

我有 proj1.dll,它依赖于另一个 DLL,proj2.dll。我在 VS2013 中编译 proj2.dll 时针对编译器输出的导入库编译了 proj1.dll。我还导出了我有兴趣使用的公共函数。所以现在我有两个独立的 DLL,它们都符合“cdll”标准。

我想在 Python 中使用 proj1.dll,但遇到以下问题:

import ctypes

# Crashes saying no entry point for "some_func" in proj2.dll
ctypes.cdll.LoadLibrary("C:\myfolder\proj1.dll")

ctypes.cdll.LoadLibrary("C:\myfolder\proj2.dll") # Loads fine
ctypes.cdll.LoadLibrary("C:\myfolder\proj1.dll") # Loads fine if proj2 is loaded first

以前,当我将 proj2 构建为静态库并在 proj1 中链接它时,从 Python 调用此 DLL 是可行的。这两个 DLL 存在于同一个文件夹中。我什至尝试将文件夹的路径添加到我的 PATH 环境变量中,以查看这是否是路径问题,但没有任何改变。

我假设 Windows 会加载 proj1.dll 然后加载 dll 的依赖项。我错了吗?调用者(Python)是否必须首先加载依赖 DLL?有人知道为什么会这样吗?

【问题讨论】:

  • myfolder 在您的路径中吗?您可能需要检查您的 proj1.dll 以确认它包含依赖项。 stackoverflow.com/questions/7378959/…
  • Python 版本是什么?错误是什么?
  • @CristiFati 我不确定 OP 是否还在回答您的问题。我确实打开了赏金,因为我有一个非常相似的问题 (stackoverflow.com/questions/61717476/…),并认为对这个问题的更完整的答案也会回答我的问题(我会关闭我的问题,因为在此处发布了一个很好的答案)。随意检查其他问题并在那里提问,也许我会反过来做。
  • @Holt:所以,这是一个不同于指出问题的问题。

标签: python c++ dll loadlibrary


【解决方案1】:

您需要确保您的环境路径包含依赖项的路径。这将起作用。

import os
from ctypes import *

path_to_deps = "C:\\myfolder"
os.environ['PATH'] = path_to_deps + os.pathsep + os.environ['PATH']
d = CDLL("C:\myfolder\proj2.dll")

更新:

python 3.8 update notes 中添加了调用os.add_dll_directory(path),用于指定要搜索的dll 目录。

【讨论】:

    【解决方案2】:

    上市[Python 3.Docs]: ctypes - A foreign function library for Python

    鉴于提出问题的时间,Python 3.8 可以排除(但[SO]: PyWin32 and Python 3.8.0 (@CristiFati's answer) 可能仍然很有趣)。

    对于 .dll 加载泛型,[SO]: Python Ctypes - loading dll throws OSError: [WinError 193] %1 is not a valid Win32 application (@CristiFati's answer) 可能包含有用的信息。

    现在,问题不完全是 MCVEREPREX ([SO]: How to create a Minimal, Reproducible Example (reprex (mcve))),但我认为如果是,答案可能很明显,因此不需要这个问题:)

    调查

    错误是ERROR_PROC_NOT_FOUND1270x7F)。

    注意.dll仅在其所有依赖项都已成功加载(递归)后才会加载。如果其中一个依赖项失败,则失败会一直传播到顶部,并且(原始).dll 加载失败并出现该错误。

    在这两种情况下(自动)会发生什么:

    • 成功

      1. proj2 已找到并尝试加载。成功了
      2. proj1 发现试图加载

        1. 由于它取决于 proj2,因此尝试在 1st 加载
        2. proj2 已经在内存中(来自 #1.
        3. proj1 所需的 proj2 函数在 proj2 中搜索。都找到了


        结果,这一步 (#2.) 也成功了

    • 失败

      1. proj1 被发现试图被加载
        1. 由于它取决于 proj2,因此尝试在 1st 加载
        2. proj2 已找到并已加载(如果没有,错误将是 ERROR_MOD_NOT_FOUND
        3. proj1 所需的 proj2 函数在 proj2 中搜索。显然,(至少)一个,找不到并且程序崩溃

    从上面只能得出结论,%PATH% 中某处有一个proj2.dll,并且是由OS 加载 proj1.dll
    它不是 C:\myfolder\proj2.dll。它可能是不导出所需功能的旧版本,或者是完全不相关的另一个版本。

    我设法用 2 个简单(依赖).dll 和一个 .exe(如果需要,我还会发布代码)重现崩溃:

    (最简单的)解决方案是proj2.dll(右侧)的目录“C:\myfolder”添加到 %PATH% ,在加载 proj1.dll 之前。查看[MS.Docs]: Dynamic-Link Library Search Order,注意以下几个方面:

    • 追加(在最后)不行,因为错误的.dll dir 已经在%PATH%(在右边的之前),错误的 .dll 将被找到(并加载)1st
    • 您必须在 错误的 dir 之前添加它(或者更好:从 %PATH% 中删除错误的 dir共)。要检查它在哪里,请使用(在 cmd 中)终端:

      where proj2.dll
      
    • 由于不知道.dlldir的位置在%PATH%哪里错了,添加右边.dll %PATH% 开头的 dir 将是 OK。就个人而言,我不认为在 Win 系统之前添加目录是一种好习惯

    • 但是,如果 proj2.dll 位于“%SystemRoot%\System32”下,则必须删除(或重命名)它(文件)李>

    无论如何,%PATH% 改变可以做到:

    • 在开始Python之前:

      set PATH=C:\myfolder;%PATH%
      
    • 来自 Python 本身:

      os.environ["PATH"] = "C:\myfolder;" + os.environ["PATH"]
      

      对于Python 3.8,查看答案开头的相关URL

    一个很好的(静态).dll依赖检查工具是Dependency Walker

    【讨论】:

      【解决方案3】:

      可能需要为您的项目更改构建设置..

      看看这是否有帮助:Copying a DLL's dependencies in Visual Studio

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-10
        • 1970-01-01
        • 2011-02-24
        • 1970-01-01
        • 2013-03-16
        • 1970-01-01
        • 1970-01-01
        • 2021-08-05
        相关资源
        最近更新 更多