Python |访问dll使用ctypes [英] Python | accessing dll using ctypes

查看:490
本文介绍了Python |访问dll使用ctypes的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试访问Firefox Web浏览器附带的dll( nss3.dll )中的一些功能。为了处理这个任务,我在Python中使用了ctypes。问题在于,在将dll加载到内存的初始位置失败。

I'm trying to access some functions in a dll (nss3.dll) that ships with Firefox web browser. To handle this task I have used ctypes in Python. The problem is that it fails at the initial point which is when loading the dll in to the memory.

这是我必须这样做的代码片段。 p>

This is the code snippet that I have to do so.

>>> from ctypes import *
>>> windll.LoadLibrary("E:\\nss3.dll")

获取是

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    windll.LoadLibrary("E:\\nss3.dll")
  File "C:\Python26\lib\ctypes\__init__.py", line 431, in LoadLibrary
    return self._dlltype(name)
  File "C:\Python26\lib\ctypes\__init__.py", line 353, in __init__
    self._handle = _dlopen(self._name, mode)
WindowsError: [Error 126] The specified module could not be found

我还尝试从Firefox安装路径加载它,假设有可能依赖。

I also tried loading it from the Firefox installation path assuming that there maybe dependencies.

>>> windll.LoadLibrary("F:\\Softwares\\Mozilla Firefox\\nss3.dll")

但是我得到与上述相同的异常。

But I'm getting the same exception as mentioned above.

谢谢。

推荐答案

nss3.dll链接到以下DLL,它们都位于Firefox目录中:nssutil3.dll,plc4.dll,plds4.dll,nspr4.dll和mozcrt19.dll。系统库加载程序在进程的DLL搜索路径中查找这些文件,其中包括应用程序目录,系统目录,当前目录以及 PATH 环境变量。

nss3.dll is linked to the following DLLs, which are all located in the Firefox directory: nssutil3.dll, plc4.dll, plds4.dll, nspr4.dll, and mozcrt19.dll. The system library loader looks for these files in the DLL search path of the process, which includes the application directory, system directories, the current directory, and each of the directories listed in the PATH environment variable.

最简单的解决方案是将当前目录更改为DLL Firefox目录。但是,这不是线程安全的,所以我一般不会依赖它。另一个选项是将Firefox目录附加到 PATH 环境变量中,这是我在原始版本的答案中所建议的。但是,这并不比修改当前目录要好。

The simplest solution is to change the current directory to the DLL Firefox directory. However, that's not thread safe, so I wouldn't rely on it in general. Another option is to append the Firefox directory to the PATH environment variable, which is what I suggested in my original version of this answer. However, that's not much better than modifying the current directory.

较新版本的Windows(NT 6.0+,更新版本KB2533623)允许通过 SetDefaultDllDirectories AddDllDirectory RemoveDllDirectory 。但是,这种做法会超过这里。

Newer versions of Windows (NT 6.0+ with update KB2533623) allow the DLL search path to be updated in a thread-safe manner via SetDefaultDllDirectories, AddDllDirectory, and RemoveDllDirectory. But that approach would be over the top here.

在这种情况下,为了既简单又兼容旧版本的Windows,只需调用 LoadLibraryEx 标记为 LOAD_WITH_ALTERED_SEARCH_PATH 。您需要使用绝对路径加载DLL,否则行为是未定义的。为方便起见,我们可以将 ctypes.CDLL ctypes.WinDLL 继承 LoadLibraryEx 而不是 LoadLibrary

In this case, for the sake of both simplicity and compatibility with older versions of Windows, it suffices to call LoadLibraryEx with the flag LOAD_WITH_ALTERED_SEARCH_PATH. You need to load the DLL using an absolute path, else the behavior is undefined. For convenience we can subclass ctypes.CDLL and ctypes.WinDLL to call LoadLibraryEx instead of LoadLibrary.

import os
import ctypes

if os.name == 'nt':
    from ctypes import wintypes

    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

    def check_bool(result, func, args):
        if not result:
            raise ctypes.WinError(ctypes.get_last_error())
        return args

    kernel32.LoadLibraryExW.errcheck = check_bool
    kernel32.LoadLibraryExW.restype = wintypes.HMODULE
    kernel32.LoadLibraryExW.argtypes = (wintypes.LPCWSTR,
                                        wintypes.HANDLE,
                                        wintypes.DWORD)

class CDLLEx(ctypes.CDLL):
    def __init__(self, name, mode=0, handle=None, 
                 use_errno=True, use_last_error=False):
        if os.name == 'nt' and handle is None:
            handle = kernel32.LoadLibraryExW(name, None, mode)
        super(CDLLEx, self).__init__(name, mode, handle,
                                     use_errno, use_last_error)

class WinDLLEx(ctypes.WinDLL):
    def __init__(self, name, mode=0, handle=None, 
                 use_errno=False, use_last_error=True):
        if os.name == 'nt' and handle is None:
            handle = kernel32.LoadLibraryExW(name, None, mode)
        super(WinDLLEx, self).__init__(name, mode, handle,
                                       use_errno, use_last_error)

可用 LoadLibraryEx flags:

DONT_RESOLVE_DLL_REFERENCES         = 0x00000001
LOAD_LIBRARY_AS_DATAFILE            = 0x00000002
LOAD_WITH_ALTERED_SEARCH_PATH       = 0x00000008
LOAD_IGNORE_CODE_AUTHZ_LEVEL        = 0x00000010  # NT 6.1
LOAD_LIBRARY_AS_IMAGE_RESOURCE      = 0x00000020  # NT 6.0
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE  = 0x00000040  # NT 6.0

# These cannot be combined with LOAD_WITH_ALTERED_SEARCH_PATH.
# Install update KB2533623 for NT 6.0 & 6.1.
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR    = 0x00000100
LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200
LOAD_LIBRARY_SEARCH_USER_DIRS       = 0x00000400
LOAD_LIBRARY_SEARCH_SYSTEM32        = 0x00000800
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS    = 0x00001000

例如:

firefox_path = r'F:\Softwares\Mozilla Firefox'
nss3 = CDLLEx(os.path.join(firefox_path, 'nss3.dll'), 
              LOAD_WITH_ALTERED_SEARCH_PATH)

nss3.NSS_GetVersion.restype = c_char_p

>>> nss3.NSS_GetVersion()                 
'3.13.5.0 Basic ECC'

这篇关于Python |访问dll使用ctypes的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆