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

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

问题描述

我正在尝试访问 Firefox 网络浏览器附带的 dll (nss3.dll) 中的某些功能.为了处理这个任务,我在 Python 中使用了 ctypes.问题是它在初始点失败,即在将 dll 加载到内存中时.

这是我必须这样做的代码片段.

<预><代码>>>>从 ctypes 导入 *>>>windll.LoadLibrary("E:\nss3.dll")

我得到的例外是

回溯(最近一次调用最后一次):文件<pyshell#2>",第 1 行,在 <module> 中windll.LoadLibrary("E:\nss3.dll")LoadLibrary 中的文件C:Python26libctypes\__init__.py",第 431 行返回 self._dlltype(name)文件C:Python26libctypes\__init__.py",第 353 行,在 __init__ 中self._handle = _dlopen(self._name, mode)WindowsError: [错误 126] 找不到指定的模块

假设可能存在依赖关系,我还尝试从 Firefox 安装路径加载它.

<预><代码>>>>windll.LoadLibrary("F:\Softwares\Mozilla Firefox\nss3.dll")

但我遇到了与上述相同的异常.

谢谢.

解决方案

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

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

较新版本的 Windows(NT 6.0+ 更新 KB2533623)允许通过 SetDefaultDllDirectoriesAddDllDirectorySetDefaultDllDirectories 以线程安全的方式更新 DLL 搜索路径代码>RemoveDllDirectory.但这种方法在这里是过分的.

在这种情况下,为了简单起见并与旧版本的 Windows 兼容,只需使用标志 LOAD_WITH_ALTERED_SEARCH_PATH 调用 LoadLibraryEx 就足够了.您需要使用绝对路径加载 DLL,否则行为未定义.为方便起见,我们可以将 ctypes.CDLLctypes.WinDLL 子类化以调用 LoadLibraryEx 而不是 LoadLibrary.

导入操作系统导入 ctypes如果 os.name == 'nt':从 ctypes 导入 wintypeskernel32 = ctypes.WinDLL('kernel32', use_last_error=True)def check_bool(result, func, args):如果不是结果:引发 ctypes.WinError(ctypes.get_last_error())返回参数kernel32.LoadLibraryExW.errcheck = check_boolkernel32.LoadLibraryExW.restype = wintypes.HMODULEkernel32.LoadLibraryExW.argtypes = (wintypes.LPCWSTR,wintypes.HANDLE,wintypes.DWORD)类 CDLLEx(ctypes.CDLL):def __init__(self, name, mode=0, handle=None,use_errno=True,use_last_error=False):如果 os.name == 'nt' 并且句柄为 None:handle = kernel32.LoadLibraryExW(name, None, mode)super(CDLLEx, self).__init__(name, mode, handle,use_errno, use_last_error)类 WinDLLEx(ctypes.WinDLL):def __init__(self, name, mode=0, handle=None,use_errno=False,use_last_error=True):如果 os.name == 'nt' 并且句柄为 None:handle = kernel32.LoadLibraryExW(name, None, mode)super(WinDLLEx, self).__init__(name, mode, handle,use_errno, use_last_error)

以下是所有可用的 LoadLibraryEx 标志:

DONT_RESOLVE_DLL_REFERENCES = 0x00000001LOAD_LIBRARY_AS_DATAFILE = 0x00000002LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010 # NT 6.1LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020 # NT 6.0LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040 # NT 6.0# 这些不能与 LOAD_WITH_ALTERED_SEARCH_PATH 结合使用.# 为 NT 6.0 & 安装更新 KB25336236.1.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000

例如:

firefox_path = r'F:SoftwaresMozilla 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 基本 ECC'

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.

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

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

The exception I'm getting is

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

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.

Thanks.

解决方案

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.

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.

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.

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)

Here are all of the available 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

For example:

firefox_path = r'F:SoftwaresMozilla 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'

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

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