Python ctypes:从相对路径加载 DLL
Posted
技术标签:
【中文标题】Python ctypes:从相对路径加载 DLL【英文标题】:Python ctypes: loading DLL from from a relative path 【发布时间】:2011-02-28 03:47:31 【问题描述】:我有一个 Python 模块 wrapper.py
,它包装了一个 C DLL。 DLL 与模块位于同一文件夹中。因此,我使用下面的代码来加载它:
myDll = ctypes.CDLL("MyCDLL.dll")
如果我从它自己的文件夹中执行wrapper.py
,这将有效。但是,如果我从其他地方运行它,它就会失败。这是因为 ctypes 会计算相对于当前工作目录的路径。
我的问题是,有没有一种方法可以指定 DLL 相对于包装器的路径而不是当前工作目录?这将使我能够将两者一起发布,并允许用户从任何地方运行/导入包装器。
【问题讨论】:
我使用selected answer 中的方法,但在一种情况下,我有一个从另一个 dll 导入导出的 dll,它不会加载。解决方案是先加载另一个 dll,例如:_DIRNAME = os.path.dirname(__file__); required_dll = ctypes.cdll.LoadLibrary(os.path.join(_DIRNAME, required.dll)); main_dll = ctypes.cdll.LoadLibrary(os.path.join(_DIRNAME, main.dll))
瞧,这行得通!
【参考方案1】:
可以使用os.path.dirname(__file__)
获取Python源文件所在目录。
【讨论】:
非常感谢。这正是我想要的。 这样的相对路径可以正常工作,不需要os.path.abspath()
或将此路径添加到$PATH
(%PATH%
)。需要注意的是,如果您的 dll 需要另一个 dll,那么您也必须加载它,在加载此之前,请参阅我在 OP 问题下的评论。【参考方案2】:
我总是将我的 DLL 所在的目录添加到路径中。这行得通:
os.environ['PATH'] = os.path.dirname(__file__) + ';' + os.environ['PATH']
windll.LoadLibrary('mydll.dll')
请注意,如果您使用 py2exe,这将不起作用(因为未设置 __file__
)。在这种情况下,您需要依赖sys.executable
属性(完整说明在http://www.py2exe.org/index.cgi/WhereAmI)
【讨论】:
os.pathsep
是平台安全的方式,用于指示系统中路径条目之间使用的分隔符 $PATH
或 %PATH%
环境变量。但是,我不提倡这个答案,因为 IMO 在运行时编辑环境变量是不符合标准的; IMO 它们应该在安装过程中由setup.py
设置。相反,我认为 selected answer 可以解决问题!
@MarkMikofski 太傻了。任何编辑环境变量的应用程序都是唯一能看到更改的应用程序。他们不坚持。如果他们这样做,那将是一场安全噩梦。 setup.py 无论如何都无法更改正在运行的应用程序的环境变量。随心所欲地编辑您的环境。
@tritium21 这不是我发表评论的原因,尽管我认为我对设置 PATH
和 sys.path
感到困惑。总的来说,我认为任何稳健、简单和广泛实践的都是最好的。 IMO 将 DLL 的位置添加到 PATH
不如仅使用 DLL 完整路径强大。
@tritium21 顺便说一句:爱你的手柄
请注意,将 DLL 目录添加到 PATH 环境变量中不再适用于 Python 3.8+。您需要改为调用新的os.add_dll_directory(<path>)
(您可能希望有条件地调用它 - hasattr(os, "add_dll_directory"): ...
- 否则为 Python 3.7 及更低版本修改 PATH。另请参阅 docs.python.org/3.8/whatsnew/3.8.html#changes-in-the-python-api【参考方案3】:
扩展马修的回答:
import os.path
dll_name = "MyCDLL.dll"
dllabspath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + dll_name
myDll = ctypes.CDLL(dllabspath)
这仅适用于脚本,不适用于控制台或 py2exe
。
【讨论】:
我一般喜欢使用 os.path.sep,但是有没有不使用 ';' 的 Windows 安装路径分隔符? 此路径分隔符是目录分隔符,即 Windows 上的“\”。这与您的方法不同,通过其绝对文件路径加载 dll,而不是修改 PATH 环境变量。我想我更喜欢你的,因为如果没有提供默认系统 dll,它可以回退加载。os.path.join
对手指和眼睛来说更容易。例如:os.path.abspath(os.path.join(os.path.dirname(__file__), dll_name))
我认为Chris B. 将os.pathsep
与os.sep
混淆了。仅供参考:os.sep
和 os.path.sep
是等价的。【参考方案4】:
另一个版本:
dll_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'MyCDLL.dll')
myDll = ctypes.CDLL(dll_file)
【讨论】:
以上是关于Python ctypes:从相对路径加载 DLL的主要内容,如果未能解决你的问题,请参考以下文章