'Can't import dll module in Python

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

  • win 10 64 bit
  • python 3.8 64 bit
  • libusb 1.022
  • libuvc.dll compiled with MinGW64

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.



Solution 1:[1]

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}")

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.

Solution 2:[2]

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://docs.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

Solution 3:[3]

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.

Solution 4:[4]

You can specify the path to the library

import snap7
import struct
from snap7.common import Snap7Library
from snap7.util import *

# If you are using a different location for the library
Snap7Library(lib_location='C:/snap7/snap7.dll')
load_library() #Testing library is correctly <WinDLL 'C:\snap7\snap7.dll', handle 7ff9d5d90000 at 0x1a5a0417640>

plc = snap7.client.Client()
plc.connect("10.112.115.10",0,1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 tigonza
Solution 4 Machavity