Python |访问dll使用ctypes [英] Python | accessing dll using 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 $ c $中列出的每个目录c>环境变量。
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屋!