无法在Python中导入dll模块

20

我已经紧张了几天,试图在Windows上编译修改过的libuvc版本,现在终于完成了,但是似乎无法在Python中加载它。这个我已经编译并成功导入到Linux机器上使用相同版本Python的库,在w10上根本不起作用。

系统

  • Win 10 64位
  • Python 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)

我得到了以下错误:

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!
问题在于该文件已存在,因为它被util.find_library找到,但Python认为它不在那个位置,或者输出只是默认值。我在这里错过了什么?可能无法加载模块,但却无法找到它?很抱歉,我没有比这更多的输出。

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


也许与该文件的权限有关?尝试使用进程监视器查看访问该文件时发生了什么。 - Pedro Rodrigues
有哪些错误信息可以指示权限错误?因为在进程监视器中有很多反馈。我应该寻找什么?有很多DLL的成功读取。 - tigonza
按照你尝试访问的路径进行筛选。或者尝试计算结果列,查找一些权限被拒绝或类似的情况。 - Pedro Rodrigues
请参考此答案了解如何使用进程监视器来查找DLL问题。可能是在不同路径中的依赖DLL找不到,因此仅限于路径可能会错过某些内容。请通过进程和CreateFile进行限制,并在尝试加载DLL后查看列表末尾。 - Mark Tolonen
我已经自作主张向Python提交了一个小错误报告,以解决文档和实际行为之间的差异:https://bugs.python.org/issue42114 - Mad Physicist
有人能告诉我Python中的“构造函数语法”是什么意思吗? - Beast
6个回答

25
一年晚了,但我已经搞清楚了发生了什么以及如何修复它。如果您查看约在第340行左右的ctypes.CDLL代码,您会发现文档实际上是不正确的。该代码将构造函数定义为:
def __init__(self, name, mode=DEFAULT_MODE, handle=None,
             use_errno=False, use_last_error=False, winmode=None):
然而,文档中说winmode=0。如果你看一下第358行,你会发现这非常重要。当winmode=None时,_ctypes.LoadLibrary第374行(在第110行别名为_dlopen)使用的搜索模式设置为nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS。这种搜索模式似乎不会响应对os.environ ['PATH']sys.pathos.add_dll_directory的更改。

然而,如果你绕过该设置,使用winmode=0而不是None,库似乎可以正常加载。零是一个有效的模式,可以作为完整路径(如nt._LOAD_WITH_ALTERED_SEARCH_PATH)。这里https://learn.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


@CristiFati。在win 10上无法工作。我本来期望标志能够像你描述的那样工作。也许Eryk所提到的安全性有所不同。 - Mad Physicist
如果您想进行安全加载,必须分析依赖的DLL。首先使用winmode=0尝试。然后在Process Explorer中,将底部窗格视图切换为显示已加载DLL的完整路径。在调用ctypes.CDLL之前,除了python.exe的应用程序目录、System32目录和包含直接通过ctypes.CDLL加载的DLL的目录之外,所有目录都必须手动添加os.add_dll_directory。如果依赖项在DLL目录中,请确保传递给CDLL的路径是合格的,以便包含其目录进行搜索。 - Eryk Sun
@ErykSun。感谢您的提示。我仔细地添加了所有依赖文件夹,一切都按预期开始工作了。 - Mad Physicist
@ErykSun。我会在今晚阅读您所做的评论以及其他一些内容,并重新撰写这个答案。 - Mad Physicist
@bomben。在评论中提出那些需要详细解答的问题并不是一个好主意。请使用 [mcve] 提交一个单独的问题。 - Mad Physicist
显示剩余10条评论

24

Python 3.8 开始,.dll 的搜索机制已经改变(仅限于 Windows)。

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

将路径添加到 DLL 搜索路径中。

当解析导入的扩展模块的依赖项时(模块本身通过 sys.path 解析),以及由 ctypes 使用时,将使用此搜索路径。

...

可用性:Windows

因此,您可以执行以下操作:

os.add_dll_directory("${path_to_working_dlls_directoy}")

${path_to_working_dlls_directoy} 是一个占位符,代表实际路径,需要替换为实际路径。

您可以查看[SO]: PyWin32 and Python 3.8.0 (@CristiFati's answer)(尽管它看起来非常不同,但有相同的原因),以获取更多详细信息。

P.S.Nix OS 不受影响。



更新#0

虽然我基于(官方)文档回答了问题,但[SO]: Can't import dll module in Python (@MadPhysicist's answer)(顺便说一句,非常好的回答)提供了“为什么”的部分。
然而,还有一些需要澄清的方面。

我关于os.add_dll_directory的所有陈述都是正确的,并且仍然适用。根据[MS.Learn]: LoadLibraryExA function (libloaderapi.h)重点是我的):

  • LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
    0x00001000

    该值是LOAD_LIBRARY_SEARCH_APPLICATION_DIRLOAD_LIBRARY_SEARCH_SYSTEM32LOAD_LIBRARY_SEARCH_USER_DIRS的组合。不会搜索标准搜索路径中的目录。该值不能与LOAD_WITH_ALTERED_SEARCH_PATH组合使用。
    该值代表应用程序应在其DLL搜索路径中包含的建议最大目录数。

  • LOAD_LIBRARY_SEARCH_USER_DIRS
    0x00000400

    如果使用此值,则会搜索使用AddDllDirectorySetDllDirectory函数添加的目录以查找DLL及其依赖项。

这是默认使用的机制 (winmode=None,将 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 传递给 LoadLibraryEx)。
当设置 winmode=0 时,Win 的默认搜索机制启动。[MS.Learn]: Dynamic-Link Library Search Order - Standard Search Order for Desktop Applications 表示(最后一项 - 不考虑 SafeDllSearchMode强调 仍然属于我自己):

  1. 列在 PATH 环境变量中的目录。请注意,这不包括由 App Paths 注册表键指定的每个应用程序路径。计算 DLL 搜索路径时,不使用 App Paths 键。

我准备了一个小例子。
Python 代码尝试加载(通过 CTypes)位于同一 dir 中的 dll00.dll,而该文件又链接到(依赖于)位于不同 dirsubdir00)中的另一个文件(dll01.dll)。

  • dll00.c:

    #include <stdio.h>
    
    #if defined(_WIN32)
    #  define DLL00_EXPORT_API __declspec(dllexport)
    #else
    #  define DLL00_EXPORT_API
    #endif
    
    
    int dll01Func00();
    
    #if defined(__cplusplus)
    extern "C" {
    #endif
    
    DLL00_EXPORT_API int dll00Func00();
    
    #if defined(__cplusplus)
    }
    #endif
    
    
    int dll00Func00() {
        printf("%s - %d - %s\n", __FILE__, __LINE__, __FUNCTION__);
        dll01Func00();
        return 0;
    }
    
  • dll01.c:

    #include <stdio.h>
    
    #if defined(_WIN32)
    #  define DLL01_EXPORT_API __declspec(dllexport)
    #else
    #  define DLL01_EXPORT_API
    #endif
    
    
    #if defined(__cplusplus)
    extern "C" {
    #endif
    
    DLL01_EXPORT_API int dll01Func00();
    
    #if defined(__cplusplus)
    }
    #endif
    
    
    int dll01Func00() {
        printf("%s - %d - %s\n", __FILE__, __LINE__, __FUNCTION__);
        return 0;
    }
    
  • code00.py:

    #!/usr/bin/env python
    
    import argparse
    import ctypes as cts
    import os
    import sys
    
    
    DLL_NAME = "./dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")
    
    METH_ADDLLDIR = "a"
    METH_PATH = "p"
    METHS = (
        METH_ADDLLDIR,
        METH_PATH,
    )
    
    
    def parse_args(*argv):
        parser = argparse.ArgumentParser(description="Python .dll search path (Win) example")
        parser.add_argument("--path", "-p", choices=METHS)
        parser.add_argument("--winmode", "-w", type=int)
    
        args, unk = parser.parse_known_args()
        if unk:
            print("Warning: Ignoring unknown arguments: {:}".format(unk))
        return args.path, args.winmode
    
    
    def main(*argv):
        meth, wmod = parse_args()
        print("PATH (original): {:}\n".format(os.environ.get("PATH")))
        print("Using winmode={:}".format(wmod))
        if meth is not None:
            subdir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "subdir00")
            if meth == METH_ADDLLDIR:
                add_dll_directory = getattr(os, "add_dll_directory", None)
                if add_dll_directory:
                    os.add_dll_directory(subdir)
                    print("Using AddDllDirectory()\n")
            elif meth == METH_PATH:
                os.environ["PATH"] = os.pathsep.join((os.environ.get("PATH", ""), subdir))
                print("Using %PATH%\n")
        dll00 = cts.CDLL(DLL_NAME, winmode=wmod)
        print("Dll: {:}".format(dll00))
        if False:  # No need to actually call the function
            dll00Func00 = dll00.dll00Func00
            dll00Func00.argtypes = ()
            dll00Func00.restype = cts.c_int
            res = dll00Func00()
            print("\n{0:s} returned: {1:d}".format(dll00Func00.__name__, res))
    
    
    if __name__ == "__main__":
        print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                       64 if sys.maxsize > 0x100000000 else 32, sys.platform))
        rc = main(*sys.argv[1:])
        print("\nDone.\n")
        sys.exit(rc)
    

注意:

  • 这里有两个变量(可通过命令行参数进行更改):

    • path - 如何将 subdir00 添加到 .dll 搜索路径中:

      1. 什么都不做(不添加)

      2. 传递给 os.add_dll_directory

      3. 附加到 %PATH%

    • winmode - 将其传递给 CDLL 初始化程序(仅说明 0None

    因此,会出现6种组合

输出:

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q059330863]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul

[prompt]> tree /a /f
Folder PATH listing for volume SSD0-WORK
Volume serial number is AE9E-72AC
E:.
|   code00.py
|   dll00.c
|   dll01.c
|   test.bat
|
\---subdir00

[prompt]> :: Build .dlls
[prompt]> cl /nologo /DDLL /MD dll01.c  /link /NOLOGO /DLL /OUT:subdir00\dll01.dll
dll01.c
   Creating library subdir00\dll01.lib and object subdir00\dll01.exp

[prompt]>
[prompt]> cl /nologo /DDLL /MD dll00.c  /link /NOLOGO /DLL /OUT:dll00.dll subdir00\dll01.lib
dll00.c
   Creating library dll00.lib and object dll00.exp

[prompt]>
[prompt]> tree /a /f
Folder PATH listing for volume SSD0-WORK
Volume serial number is AE9E-72AC
E:.
|   code00.py
|   dll00.c
|   dll00.dll
|   dll00.exp
|   dll00.lib
|   dll00.obj
|   dll01.c
|   dll01.obj
|   test.bat
|
\---subdir00
        dll01.dll
        dll01.exp
        dll01.lib


[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" code00.py -h
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec  6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32

usage: code00.py [-h] [--path {a,p}] [--winmode WINMODE]

Python .dll search path (Win) example

options:
  -h, --help            show this help message and exit
  --path {a,p}, -p {a,p}
  --winmode WINMODE, -w WINMODE

[prompt]>
[prompt]> :: Going through combinations. When an argument is not passed, its default value is None
[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" code00.py
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec  6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32

PATH (original): c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\VCPackages;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TestWindow;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\MSBuild\Current\bin\Roslyn;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4
.8 Tools\x64\;C:\Program Files (x86)\HTML Help Workshop;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\devinit;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\\MSBuild\Current\Bin;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Install\pc064\Docker\Docker\Version\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\dotnet\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts;C:\Us
ers\cfati\AppData\Local\Microsoft\WindowsApps;C:\Users\cfati\.dotnet\tools;;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\Linux\bin\ConnectionManagerExe

Using winmode=None
Traceback (most recent call last):
  File "e:\Work\Dev\StackOverflow\q059330863\code00.py", line 57, in <module>
    rc = main(*sys.argv[1:])
  File "e:\Work\Dev\StackOverflow\q059330863\code00.py", line 44, in main
    dll00 = cts.CDLL(DLL_NAME, winmode=wmod)
  File "c:\Install\pc064\Python\Python\03.10\lib\ctypes\__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
FileNotFoundError: Could not find module 'e:\Work\Dev\StackOverflow\q059330863\dll00.dll' (or one of its dependencies). Try using the full path with constructor syntax.

[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" code00.py -w 0
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec  6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32

PATH (original): c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\VCPackages;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TestWindow;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\MSBuild\Current\bin\Roslyn;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4
.8 Tools\x64\;C:\Program Files (x86)\HTML Help Workshop;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\devinit;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\\MSBuild\Current\Bin;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Install\pc064\Docker\Docker\Version\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\dotnet\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts;C:\Us
ers\cfati\AppData\Local\Microsoft\WindowsApps;C:\Users\cfati\.dotnet\tools;;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\Linux\bin\ConnectionManagerExe

Using winmode=0
Traceback (most recent call last):
  File "e:\Work\Dev\StackOverflow\q059330863\code00.py", line 57, in <module>
    rc = main(*sys.argv[1:])
  File "e:\Work\Dev\StackOverflow\q059330863\code00.py", line 44, in main
    dll00 = cts.CDLL(DLL_NAME, winmode=wmod)
  File "c:\Install\pc064\Python\Python\03.10\lib\ctypes\__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
FileNotFoundError: Could not find module './dll00.dll' (or one of its dependencies). Try using the full path with constructor syntax.

[prompt]>
[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" code00.py -p a
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec  6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32

PATH (original): c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\VCPackages;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TestWindow;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\MSBuild\Current\bin\Roslyn;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4
.8 Tools\x64\;C:\Program Files (x86)\HTML Help Workshop;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\devinit;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\\MSBuild\Current\Bin;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Install\pc064\Docker\Docker\Version\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\dotnet\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts;C:\Us
ers\cfati\AppData\Local\Microsoft\WindowsApps;C:\Users\cfati\.dotnet\tools;;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\Linux\bin\ConnectionManagerExe

Using winmode=None
Using AddDllDirectory()

Dll: <CDLL 'e:\Work\Dev\StackOverflow\q059330863\dll00.dll', handle 7ffe6aaf0000 at 0x1f896d9ffd0>

Done.


[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" code00.py -p a -w 0
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec  6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32

PATH (original): c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\VCPackages;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TestWindow;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\MSBuild\Current\bin\Roslyn;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4
.8 Tools\x64\;C:\Program Files (x86)\HTML Help Workshop;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\devinit;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\\MSBuild\Current\Bin;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Install\pc064\Docker\Docker\Version\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\dotnet\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts;C:\Us
ers\cfati\AppData\Local\Microsoft\WindowsApps;C:\Users\cfati\.dotnet\tools;;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\Linux\bin\ConnectionManagerExe

Using winmode=0
Using AddDllDirectory()

Traceback (most recent call last):
  File "e:\Work\Dev\StackOverflow\q059330863\code00.py", line 57, in <module>
    rc = main(*sys.argv[1:])
  File "e:\Work\Dev\StackOverflow\q059330863\code00.py", line 44, in main
    dll00 = cts.CDLL(DLL_NAME, winmode=wmod)
  File "c:\Install\pc064\Python\Python\03.10\lib\ctypes\__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
FileNotFoundError: Could not find module './dll00.dll' (or one of its dependencies). Try using the full path with constructor syntax.

[prompt]>
[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" code00.py -p p
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec  6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32

PATH (original): c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\VCPackages;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TestWindow;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\MSBuild\Current\bin\Roslyn;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4
.8 Tools\x64\;C:\Program Files (x86)\HTML Help Workshop;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\devinit;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\\MSBuild\Current\Bin;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Install\pc064\Docker\Docker\Version\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\dotnet\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts;C:\Us
ers\cfati\AppData\Local\Microsoft\WindowsApps;C:\Users\cfati\.dotnet\tools;;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\Linux\bin\ConnectionManagerExe

Using winmode=None
Using %PATH%

Traceback (most recent call last):
  File "e:\Work\Dev\StackOverflow\q059330863\code00.py", line 57, in <module>
    rc = main(*sys.argv[1:])
  File "e:\Work\Dev\StackOverflow\q059330863\code00.py", line 44, in main
    dll00 = cts.CDLL(DLL_NAME, winmode=wmod)
  File "c:\Install\pc064\Python\Python\03.10\lib\ctypes\__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
FileNotFoundError: Could not find module 'e:\Work\Dev\StackOverflow\q059330863\dll00.dll' (or one of its dependencies). Try using the full path with constructor syntax.

[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" code00.py -p p -w 0
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec  6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32

PATH (original): c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\VCPackages;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TestWindow;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\MSBuild\Current\bin\Roslyn;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Team Tools\Performance Tools;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4
.8 Tools\x64\;C:\Program Files (x86)\HTML Help Workshop;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\devinit;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\\MSBuild\Current\Bin;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\Tools\;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Install\pc064\Docker\Docker\Version\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\dotnet\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts;C:\Us
ers\cfati\AppData\Local\Microsoft\WindowsApps;C:\Users\cfati\.dotnet\tools;;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\Common7\IDE\VC\Linux\bin\ConnectionManagerExe

Using winmode=0
Using %PATH%

Dll: <CDLL './dll00.dll', handle 7ffe6aaf0000 at 0x142a7a73cd0>

Done.

只有2种组合(如预期)成功了(使用subdir00):

  • 将其传递给os.add_dll_directory(使用winmode None

  • 将其添加到%PATH%(使用winmode 0

结论

还有更多添加dir以搜索(依赖).dll的方法:

  1. os.add_dll_directory:

    • 默认(也是推荐的)选项(有第三方模块以这种方式加载 .dll

    • Python 加载扩展模块(.pyd)依赖项的方式一致

  2. %PATH%(和更改 winmode):

    • 适用于旧版本(< v3.8)的 Python

    • 似乎更接近于 Nix - 在那里,路径通常添加到 ${LD_LIBRARY_PATH}DYLD_LIBRARY_PATHLIBPATHSHLIB_PATH等)

    • 可以通过 winmode 的值进行自定义

  3. 更改目录.dll 位置(更像是一种解决方法):

    • 如果 .dll 存在于多个目录中,则无法工作(不能同时拥有多个 CWD

相关(或多或少):


我已经扩展了以显示搜索机制中确切的更改。 - Mad Physicist
为了提醒自己,每次来这里时,这个函数在Unix或macOS上不起作用。add_dll_directory只能在Windows上找到。 - Konchog
1
@Konchog:没错,问题标记为Windows,是关于*.dll的,doc也提到了。无论如何,我修改了答案以更明确地表达。对于其他OS,它遵循“常规”方式:例如设置LD\LIBRARY_PATH*。https://stackoverflow.com/questions/58645968/where-does-ctypes-loadlibrary-search-for-libs-on-os-x - CristiFati
在MacOS上,以下内容似乎对os.environment有影响: 'DYLD_FRAMEWORK_PATH' 'DYLD_LIBRARY_PATH' 'DYLD_FALLBACK_FRAMEWORK_PATH' 'DYLD_FALLBACK_LIBRARY_PATH' - Konchog
不行,只有winmode 1对我有效(即使没有使用os.add_dll_directory)。但是当访问函数时,它会出现分段错误。winmode 2可以编译,但无法识别我设置的一些参数的函数。我在Windows 11上使用cygwin。Python版本是3.10。 - undefined

4

我在一定程度上同意@MadPhysicist的回答,但我使用的是Python 3.9,而不是3.8,并且即使加上winmode=0,错误仍然没有消失。但是使用winmode=1,一切都正常工作!


https://dev59.com/Dn0QtIcB2Jgan1zngbnC。 - CristiFati

2

好的,我已经解决了。需要把当前工作目录切换到脚本被执行的位置,然后再从同一位置加载.dll文件。

os.chdir('path_to_working_dlls_directoy')

虽然不是完全确定为什么这会有帮助。


1
请注意,这只是一个解决方法。如果有多个带有*.dll*的文件夹,则无法正常工作。请尝试我的答案中的建议。-1。 - CristiFati

-1
只需安装“Visual Studio 2013 的 Visual C++ 可再发行程序包”,问题就会得到解决。

这是不正确的。-1。 - CristiFati

-3
您可以指定库的路径。
import snap7
import struct
from snap7.common import Snap7Library
from snap7.util import *

# If you are using a different location for the library
Snap7Library(lib_location='C:/snap7/snap7.dll')
load_library() #Testing library is correctly <WinDLL 'C:\snap7\snap7.dll', handle 7ff9d5d90000 at 0x1a5a0417640>

plc = snap7.client.Client()
plc.connect("10.112.115.10",0,1)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接