Firefox Webブラウザに付属しているdll(nss3.dll)のいくつかの関数にアクセスしようとしています。このタスクを処理するために、Pythonでctypesを使用しました。問題は、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")
しかし、上記と同じ例外が発生します。
ありがとう。
nss3.dllは、Firefoxディレクトリにある次のDLLにリンクされています:nssutil3.dll、plc4.dll、plds4.dll、nspr4.dll、およびmozcrt19.dll。システムライブラリローダーは、プロセスのDLL検索パスでこれらのファイルを検索します。これには、アプリケーションディレクトリ、システムディレクトリ、現在のディレクトリ、およびPATH
環境変数。
最も簡単な解決策は、現在のディレクトリをDLL Firefoxディレクトリに変更することです。ただし、これはスレッドセーフではないため、一般的には依存しません。別のオプションは、Firefoxディレクトリを追加することです。 PATH
環境変数に追加します。これは、この回答の元のバージョンで提案したものです。ただし、現在のディレクトリを変更するよりもはるかに優れているわけではありません。
新しいバージョンのWindows(NT 6.0+、アップデートKB2533623)では、DLL検索パスをSetDefaultDllDirectories
、AddDllDirectory
、とRemoveDllDirectory
。しかし、そのアプローチはここではやり過ぎでしょう。
この場合、単純さと古いバージョンのWindowsとの互換性の両方のために、フラグLOAD_WITH_ALTERED_SEARCH_PATH
を指定してLoadLibraryEx
を呼び出すだけで十分です。絶対パスを使用して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ソース:(拡張子が.cppのC++コードを問題なく使用できます)
#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')