Python | доступ к dll с использованием ctypes

Я пытаюсь получить доступ к некоторым функциям в dll ( nss3.dll ), который поставляется с веб-браузером Firefox. Чтобы справиться с этой задачей, я использовал ctypes в Python. Проблема в том, что он не работает в начальной точке, когда при загрузке dll в память.

Это фрагмент кода, который я должен сделать.

>>> 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, предполагая, что там могут быть зависимости.

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

Но я получаю такое же исключение, как упоминалось выше.

Благодарю.

3 Solutions collect form web for “Python | доступ к dll с использованием ctypes”

nss3.dll связан со следующими DLL-файлами, которые находятся в каталоге Firefox: nssutil3.dll, plc4.dll, plds4.dll, nspr4.dll и mozcrt19.dll. Загрузчик системной библиотеки ищет эти файлы в пути поиска DLL процесса, который включает в себя каталог приложения, системные каталоги, текущий каталог и каждую из каталогов, перечисленных в PATH среды PATH .

Самое простое решение – изменить текущий каталог на каталог DLL Firefox. Однако это не потокобезопасно, поэтому я бы не стал на это полагаться. Другой вариант – добавить каталог Firefox в PATH среды PATH , что я предложил в своей первоначальной версии этого ответа. Однако это не намного лучше, чем изменение текущего каталога.

Более поздние версии Windows (NT 6.0+ с обновлением KB2533623) позволяют отслеживать путь поиска DLL поточно-безопасным способом через AddDllDirectory , RemoveDllDirectory и RemoveDllDirectory . Но этот подход был бы наверху здесь.

В этом случае, ради простоты и совместимости со старыми версиями Windows, достаточно вызвать LoadLibraryEx с флагом LOAD_WITH_ALTERED_SEARCH_PATH . Вам нужно загрузить DLL, используя абсолютный путь, иначе поведение не определено. Для удобства мы можем подклассифицировать ctypes.CDLL и ctypes.WinDLL для вызова LoadLibraryEx вместо 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 :

 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' 

Обратите внимание, что модуль ctypes работает с расширениями C; если вы хотите написать код на C ++, вы можете сделать следующее (код C тот же):

Ваш источник dll.c: (вы можете использовать код C ++ с расширением .cpp без каких-либо проблем)

 #include <math.h> #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) double _sin(double x) { return sin(x) } #ifdef __cplusplus } #endif 

Командная строка с аутентификацией администратора:

С источником C:

 C:\Windows\system32>cl /LD "your_source_path\dll.c" /I "c:\Python33 \include" "c:\Python33\libs\python33.lib" /link/out:dll.dll 

С источником C ++:

 C:\Windows\system32>cl /LD "your_source_path\dll.cpp" /I "c:\Python33 \include" "c:\Python33\libs\python33.lib" /link/out:dll.dll 

Компилятор создает DLL-файл:

 Microsoft (R) C/C++ Optimizing Compiler Version 17.00.50727.1 for x86 Copyright (C) Microsoft Corporation. All rights reserved. dll.c // or dll.cpp Microsoft (R) Incremental Linker Version 11.00.50727.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:dll.dll /dll /implib:dll.lib /out:dll.dll dll.obj c:\Python33\libs\python33.lib Creating library dll.lib and object dll.exp 

Ваш модуль Python:

 import ctypes dll = ctypes.CDLL('your_dll_path') dll._sin.argtypes = [ctypes.c_double] dll._sin.restype = ctypes.c_double print(dll._sin(34)) # return 0.5290826861200238 

У меня была аналогичная проблема с ctypes.CDLL, и я получил ее, чтобы сменить текущий каталог на каталог библиотеки и загрузить библиотеку только по имени (я думаю, что поместить каталог в системный путь тоже будет работать). Итак, вместо

 CDLL('C:/library/path/library.dll') 

я сделал

 os.chdir('C:/library/path') CDLL('library') 
  • Получить список открытых окон в Python
  • scipy.sparse.linalg.spsolve удивительное поведение для больших разреженных матриц на Linux-системах
  • Как установить numpy 1.8 dev на Windows?
  • Перенаправление вывода django manage.py (в windows) в текстовый файл
  • Использование Windows Python из Cygwin
  • python ctype, инициализирующий структуру
  • Кросс-платформенное пространство, оставшееся на томе с использованием python
  • Установка тензорного потока с анакондой в окнах
  • Python копирует DLL на сайт-пакеты в Windows
  • Нет модуля с именем «winrandom» при использовании pycrypto
  • Написание исходных данных на физический диск (флэш-накопитель) завершается неудачей с «Плохим дескриптором файла» в окнах - Python
  • Python - лучший язык программирования в мире.