在Python中加载具有依赖项的DLL

时间:2016-09-27 20:57:11

标签: python c++ dll loadlibrary

我有proj1.dll依赖于另一个DLL proj2.dll。我在编译VS2013中的proj1.dll时编译了编译器输出的导入库proj2.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?任何人都知道为什么会这样吗?

3 个答案:

答案 0 :(得分: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目录。

答案 1 :(得分:0)

也许您的项目需要更改构建设置。

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

答案 2 :(得分:0)

列出[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)可能包含有用的信息。

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

调查

错误为 ERROR_PROC_NOT_FOUND 127 0x7F )。

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

这2种情况会自动发生:

  • 成功

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

      1. 由于依赖于 proj2 ,因此尝试加载1 st
      2. proj2 已在内存中(来自#1。
      3. proj2 中搜索 proj1 所需的 proj2 中的功能。他们都被发现


      结果,此步骤(#2。)也成功

  • 失败

      发现
    1. proj1 被尝试加载
      1. 由于依赖于 proj2 ,因此尝试加载1 st
      2. 找到并加载了
      3. proj2 (如果未加载,则错误将是 ERROR_ MOD _NOT_FOUND
      4. proj2 中搜索 proj1 所需的 proj2 中的功能。显然,(至少)一个未找到,程序崩溃了

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

我设法通过2个简单的(相关).em.dll 和一个 .exe 重现崩溃(如果需要,我还将发布代码):< / p>

img00

(最简单的)解决方案是将 proj2.dll (右)目录中的“ C:\ myfolder ”添加到%PATH% ,然后再加载 proj1.dll 。选中[MS.Docs]: Dynamic-Link Library Search Order,并牢记以下几个方面:

  • 附加(最后)不会,因为错误的 .dll dir %PATH%中(在右边的那个之前),错误的 .dll 将被发现(并加载)1 st
  • 您必须在错误的 dir 之前添加(或更妙的是,从错误的 dir 中删除错误的 dir 总计%PATH%)。要检查它在哪里,请使用(在 cmd 中)终端:

    where proj2.dll
    
  • 由于我不知道错误的 .dll dir 位置在%PATH%中,因此添加了正确的位置在%PATH%开头的 .dll 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

Dependency Walker是用于(静态) .dll 依赖项检查的出色工具。