1

I am clearly not the first one to have a problem to read a .dll file with python. Such example can be found there WindowsError: [Error 126] when loading a OS with ctypes, WindowsError: [Error 126] The specified module could not be found or https://github.com/apache/incubator-mxnet/issues/6313. Knowing the extend of issues, I checked that the path to my dll is correct. I even did a small python script to minimally test it, adding as much as needed path I could think of:

import sys
import os
from ctypes import *

if __name__ == '__main__':
    print(sys.path)
    sys.path.append(r"C:\Program Files (x86)\OpenBLAS\bin")
    pathWin = os.environ["PATH"]
    pathWin = pathWin.split(";")
    sys.path = sys.path + pathWin
    print(sys.path)
    dllToLoad = "F:/installMxnet/mxnet/build/Debug/libmxnet.dll"
    cdll.libmxnet = cdll.LoadLibrary(dllToLoad)

I still end up with this error:

Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.1.1\helpers\pydev\pydevd.py", line 1664, in <module>
    main()
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.1.1\helpers\pydev\pydevd.py", line 1658, in main
    globals = debugger.run(setup['file'], None, None, is_module)
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.1.1\helpers\pydev\pydevd.py", line 1068, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.1.1\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "main.py", line 16, in <module>
    cdll.libmxnet = cdll.LoadLibrary(dllToLoad)
  File "C:\Users\educrocq\AppData\Local\Programs\Python\Python36\lib\ctypes\__init__.py", line 426, in LoadLibrary
    return self._dlltype(name)
  File "C:\Users\educrocq\AppData\Local\Programs\Python\Python36\lib\ctypes\__init__.py", line 348, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] The specified module could not be found

According to what I read, it could be because the dll has a dependency that can't be found. (And I guess that the dependency that would not find its dependency would raise the same problem, and so on...). It seems that the problem comes from Windows which is not verbose on its output message.

But I need to know which dll can't be found in my situation, because this dll depends on lot of them... Is there a way to get which one is missing?

Emile D.
  • 602
  • 2
  • 11
  • 20
  • Try Dependency Walker. It hasn't been updated in a long time, but it should work in this case. – Eryk Sun May 24 '18 at 19:02
  • Thanks! In the meantime, it will help! However, I know I ask a lot, but it there a way to do it in the python script also? Because if I add a path in the python script, I guess that won't be seen in the external tool, but it should from cdll.loadLibrary. Shouldn't it? – Emile D. May 24 '18 at 19:16
  • 1
    IIRC, Dependency Walker can run and monitor a program, such as `python.exe script.py`. – Eryk Sun May 24 '18 at 20:08
  • Hm, good to know! I would use it in some cases! However, the documentation talks specifically about .exe (http://www.dependencywalker.com/help/html/application_profiling.htm). I tried with a .bat to be able to pass the script file as an argument, but I get an error... So it doesn't work with that. – Emile D. May 24 '18 at 21:22
  • 2
    Open python.exe. Then select Profile->Start Profiling from the menu. Add the script path to the "Program arguments". Select the options to log `DllMain` calls for process attach/detach and to hook `LoadLibrary` and `GetProcAddress` calls. Unset the other options. When it's done, check under python.exe -> python36.dll -> _ctypes.pyd -> libmxnet.dll. Ignore errrors about missing "api-*.dll" dependencies. Dependency Walker predates API sets and doesn't understand how the loader satisfies these dependencies. – Eryk Sun May 24 '18 at 22:41
  • Well, that's weird. The dll in full path doesn't seems to be found or processed. But the name of the dll (without the path) is just below and found. When I display the found dll, the full path is the same (just different case). I guess that's a bug of the software. Anyway, on the found dll, I can't expand it. But if I double click, I have a solo "out of profiling" information, that doesn't explain much more... Even weirder: when I double click, I have two dll that are in the same folder but are not found, and two other that should not be a dependency... I'm lost there... – Emile D. May 25 '18 at 20:06
  • ctypes uses a basic `LoadLibrary` call, so by default the loader won't look for dependencies in the loaded DLL's directory. For that you need `LoadLibraryEx` and the flag `LOAD_WITH_ALTERED_SEARCH_PATH`. – Eryk Sun May 26 '18 at 03:36
  • Also, `sys.path` has nothing to do with ctypes DLL loading. If all of your dependent DLLs are in "C:\Program Files (x86)\OpenBLAS\bin", then simply append that directory to `os.environ['PATH']`. – Eryk Sun May 26 '18 at 03:38

1 Answers1

1

Alright, thanks to repeated help from @eryksun and information from the C++ equivalent problem explained here, DLL Load Library - Error Code 126, I managed to find which dll was missing but not loaded. The sysinternal tool was a great help to know dynamically which one was missing. And one error I did at the time was to expect that every dll in the same folder would be loaded. In fact, the dll are loaded only when they are in the Windows path. Thus, creating a folder containing all the dll that were not solved my problem.

However, I deeply regret the lack of information provided by the error message to tell which dll was missing...

Emile D.
  • 602
  • 2
  • 11
  • 20
  • As stated in the question comments, you can load dependencies from the DLL's directory without modifying `PATH`. or any other global modifcation, by calling `LoadLibraryEx` with the flag `LOAD_WITH_ALTERED_SEARCH_PATH`. You can do this with ctypes, and even make it convenient with a [CDLLEx subclass](https://stackoverflow.com/a/23805306/205580). – Eryk Sun Jun 15 '18 at 20:09