无法在 Python 中导入 dll 模块

tig*_*nza 3 python windows winapi ctypes uvc

几天来,我一直在努力在 Windows 上编译一个修改过的 libuvc 版本,现在我终于完成了,我似乎无法在 Python 上加载它。我已经在 Linux 机器上使用相同版本的 Python 编译并成功导入的这个库根本不喜欢 w10。

系统

  • 赢得 10 64 位
  • 蟒蛇 3.8 64 位
  • libusb 1.022
  • 使用 MinGW64 编译的 libuvc.dll

问题

当尝试

import ctypes
import ctypes.util
name = ctypes.util.find_library('libuvc')
lib = ctypes.cdll.LoadLibrary(name)
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

Could not find module 'C:\Program Files (x86)\libuvc\lib\libuvc.dll'.
Try using the full path with constructor syntax. 
Error: could not find libuvc!
Run Code Online (Sandbox Code Playgroud)

问题是该文件自 util.find_library 找到以来就存在,但 python 认为它不在它所在的位置,或者输出可能只是默认值。我在这里缺少什么?不仅无法加载模块,而且无法找到它,这可能是什么原因?对不起,我没有比这更多的输出。

PS:我尝试以不同的方式重新格式化字符串,但消息没有改变。

Cri*_*ati 10

Python 3. 8 开始.dll搜索机制发生了变化。

根据[Python.Docs]: os.add_dll_directory(path)重点是我的):

添加到 DLL 搜索路径的路径。

此搜索路径用于解析导入的扩展模块的依赖项(模块本身通过 sys.path 解析),也由ctypes解析。

所以,你可以这样做:

os.add_dll_directory("${path_to_working_dlls_directoy}")
Run Code Online (Sandbox Code Playgroud)

您可以查看[SO]: PyWin32 and Python 3.8.0(@CristiFati 的回答)(虽然看起来非常不同,但原因相同),了解更多详细信息。


Mad*_*ist 6

晚了一年,但我已经弄清楚发生了什么以及如何解决它。如果您查看ctypes.CDLL大约第 340 行的代码,您会发现文档实际上是不正确的。代码将构造函数定义为

def __init__(self, name, mode=DEFAULT_MODE, handle=None,
             use_errno=False, use_last_error=False, winmode=None):
Run Code Online (Sandbox Code Playgroud)

然而,文档说winmode=0。如果您查看第 358 行,您会发现它非常重要。当winmode=None,通过所使用的搜索模式_ctypes.LoadLibrary线路374(别名为_dlopen线110)被设置为nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS线363。此搜索模式似乎不响应对os.environ['PATH']sys.path或 的更改os.add_dll_directory

但是,如果您使用winmode=0而不是绕过该设置None,则库似乎可以正常加载。零是完整路径的有效模式(就像nt._LOAD_WITH_ALTERED_SEARCH_PATH)。此处提供了完整的模式列表:https : //docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa,在dwFlags参数下。

正如@CristiFati 所指出的,Python 3.8 中的行为发生了变化。发生这种情况是因为在此之前,该winmode参数不存在。相反,mode直接使用,默认值为ctypes.DEFAULT_MODE,恰好对应于零并且适用于所有平台。

解决差异的 Python 错误报告:https : //bugs.python.org/issue42114


tig*_*nza 2

好的,所以我修复了它,需要在从同一位置加载 dll 之前将工作目录更改为执行脚本的位置。

os.chdir('path_to_working_dlls_directoy')
Run Code Online (Sandbox Code Playgroud)

但不完全确定为什么这有帮助。


归档时间:

查看次数:

14609 次

最近记录:

5 年 前