I've been stressin for a few days trying to compile a modified version of libuvc on windows and now that I've finally done it, I can't seem to load it on Python. This lib that I've already compiled and successfully imported using the same version of Python on Linux machines, doesn't like w10 at all.
System
Problem
When trying the
import ctypes
import ctypes.util
name = ctypes.util.find_library('libuvc')
lib = ctypes.cdll.LoadLibrary(name)
I get the following error:
Could not find module 'C:\Program Files (x86)\libuvc\lib\libuvc.dll'.
Try using the full path with constructor syntax.
Error: could not find libuvc!
The issue is that the file exists since it was found by util.find_library, but python doesn't think it is where it is, or maybe the output is just the default. What am I missing here? What could be failing to be unable to not just load the module, but find it? I'm sorry I don't have more output than this.
P.S: I've tried reformatting the string in different ways, but the message doesn't change.
Starting with Python 3.8, the .dll search mechanism has changed (Win specific).
According to [Python.Docs]: os.add_dll_directory(path) (emphasis is mine):
Add a path to the DLL search path.
This search path is used when resolving dependencies for imported extension modules (the module itself is resolved through sys.path), and also by ctypes.
...
Availability: Windows.
So, you could do:
os.add_dll_directory("${path_to_working_dlls_directoy}")
where ${path_to_working_dlls_directoy} is a placeholder for the actual path and it (obviously) should be replaced by it.
You can check [SO]: PyWin32 and Python 3.8.0 (@CristiFati's answer) (which although it seems very different, has the same cause), for more details.
P.S.: Nix OSes are not impacted.
A year late, but I've figured out what is going on and how to fix it. If you look at the code for ctypes.CDLL
on around line 340, you can see that the docs are actually incorrect. The code defines the constructor as
def __init__(self, name, mode=DEFAULT_MODE, handle=None,
use_errno=False, use_last_error=False, winmode=None):
The docs, however, say winmode=0
. If you look at line 358, you can see that it matters quite a bit. When winmode=None
, the search mode used by _ctypes.LoadLibrary
in line 374 (aliased as _dlopen
in line 110) is set to nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
on line 363. This search mode does not appear to respond to changes to os.environ['PATH']
, sys.path
or os.add_dll_directory
.
However, if you bypass that setting by using winmode=0
instead of None
, the library appears to load fine. Zero is a valid mode for a full path (as would be nt._LOAD_WITH_ALTERED_SEARCH_PATH
). A full list of modes is available here: https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa, under the dwFlags
parameter.
As @CristiFati indicates, the behavior changed in Python 3.8. This happened because prior to that, the winmode
parameter did not exist. Instead, mode
was used directly, with a default value of ctypes.DEFAULT_MODE
, which happens to correspond to a zero and work on all platforms.
Python bug report to resolve discrepancy: https://bugs.python.org/issue42114
OK so i fixed it, it was required that i changed the working directory to where the script was being executed before loading the dll from the same place.
os.chdir('path_to_working_dlls_directoy')
not entirely sure why this helped though.
I partially agree with @MadPhysicist's answer, but I have Python 3.9, not 3.8, and with winmode=0
error haven't disappeared. But with winmode=1
everything is working!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With