On Windows, it find_librarysearches for directories in an environment variable PATH, which is not the real search order for desktop applications used by the Windows boot loader. In particular, it find_librarydoes not include the application directory and the current directory.
Windows SearchPath , , DLL API, SetDllDirectory API SetDefaultDllDirectories AddDllDirectory.
, Windows, DLL CDLL (cdecl) WinDLL (stdcall):
nidaq_cdecl = ctypes.CDLL('NIDAQmx')
nidaq_stdcall = ctypes.WinDLL('NIDAQmx')
DLL PATH ( Linux LD_LIBRARY_PATH ). , , DLL- "dlls" . :
import os
basepath = os.path.dirname(os.path.abspath(__file__))
dllspath = os.path.join(basepath, 'dlls')
os.environ['PATH'] = dllspath + os.pathsep + os.environ['PATH']
, GetDllDirectory SetDllDirectory, , . , , PATH, , . , , CreateProcess .
import os
import ctypes
from ctypes import wintypes
from contextlib import contextmanager
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
def check_dword(result, func, args):
if result == 0:
last_error = ctypes.get_last_error()
if last_error != 0:
raise ctypes.WinError(last_error)
return args
def check_bool(result, func, args):
if not result:
last_error = ctypes.get_last_error()
if last_error != 0:
raise ctypes.WinError(last_error)
else:
raise OSError
return args
kernel32.GetDllDirectoryW.errcheck = check_dword
kernel32.GetDllDirectoryW.argtypes = (wintypes.DWORD,
wintypes.LPWSTR)
kernel32.SetDllDirectoryW.errcheck = check_bool
kernel32.SetDllDirectoryW.argtypes = (wintypes.LPCWSTR,)
@contextmanager
def use_dll_dir(dll_dir):
size = newsize = 0
while newsize >= size:
size = newsize
prev = (ctypes.c_wchar * size)()
newsize = kernel32.GetDllDirectoryW(size, prev)
kernel32.SetDllDirectoryW(os.path.abspath(dll_dir))
try:
yield
finally:
kernel32.SetDllDirectoryW(prev)
:
if __name__ == '__main__':
basepath = os.path.dirname(os.path.abspath(__file__))
dllspath = os.path.join(basepath, 'dlls')
with use_dll_dir(dllspath):
nidaq = ctypes.CDLL('NIDAQmx')
, DLL , . SetDllDirectoryW .
LoadLibraryEx LOAD_WITH_ALTERED_SEARCH_PATH, DLL . DLL, , undefined. ctypes.CDLL ctypes.WinDLL LoadLibraryEx LoadLibrary.
import ctypes
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 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 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
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040
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
:
if __name__ == '__main__':
basepath = os.path.dirname(os.path.abspath(__file__))
dllpath = os.path.join(basepath, 'dlls', 'NIDAQmx.dll')
nidaq = CDLLEx(dllpath, LOAD_WITH_ALTERED_SEARCH_PATH)