DLL найдена, но не может быть загружена из текущего рабочего каталога - PullRequest
1 голос
/ 12 октября 2019

У меня есть следующий код, который я запускаю:

def PATH():
    return "\n"+"\n".join(os.environ["PATH"].split(os.pathsep))

def syspath():
    return "\n"+"\n".join(sys.path)

def test_haha():
    logger.info(f"CWD: {os.getcwd()}")
    logger.info(f"sys.path: {syspath()}")
    logger.info(f"PATH: {PATH()}")

    logger.info(f"Found? {str(util.find_library('PCANBasic'))}")
    windll.LoadLibrary("PCANBasic")
    # pcanbasic_path = str(Path(os.getcwd()) / "PCANBasic.dll")

И мой PCANBasic.dll находится в моем рабочем каталоге. Я использую windows 10.

Если я запускаю python из командной строки, все работает правильно.

Однако у меня есть IDE, написанная на pyqt и связанная с PyInstaller. Эта IDE имеет функцию для запуска файла Python (вызывая QProcess в пакетном файле, который запускает ту же команду, которую я запускаю вручную), и в этом случае происходит сбой со следующим:

    def test_haha():
        logger.info(f"CWD: {os.getcwd()}")
        logger.info(f"sys.path: {syspath()}")
        logger.info(f"PATH: {PATH()}")

        logger.info(f"Found? {str(util.find_library('PCANBasic'))}")
>       windll.LoadLibrary("PCANBasic")

demo_test\test_dll.py:23: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
C:\Users\myuser\python3_portable\lib\ctypes\__init__.py:434: in LoadLibrary
    return self._dlltype(name)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <WinDLL 'PCANBasic', handle 0 at 0x1e9e6480668>, name = 'PCANBasic'
mode = 0, handle = None, use_errno = False, use_last_error = False

    def __init__(self, name, mode=DEFAULT_MODE, handle=None,
                 use_errno=False,
                 use_last_error=False):
self._name = name
        flags = self._func_flags_
        if use_errno:
            flags |= _FUNCFLAG_USE_ERRNO
        if use_last_error:
            flags |= _FUNCFLAG_USE_LASTERROR
        if _sys.platform.startswith("aix"):
            """When the name contains ".a(" and ends with ")",
               e.g., "libFOO.a(libFOO.so)" - this is taken to be an
               archive(member) syntax for dlopen(), and the mode is adjusted.
               Otherwise, name is presented to dlopen() as a file argument.
            """
            if name and name.endswith(")") and ".a(" in name:
                mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW )

        class _FuncPtr(_CFuncPtr):
            _flags_ = flags
            _restype_ = self._func_restype_
        self._FuncPtr = _FuncPtr

        if handle is None:
>           self._handle = _dlopen(self._name, mode)
E           OSError: [WinError 126] The specified module could not be found

CWD, sys.path идентичны, а PATH в основном одинаковы (версия IDE имеет папку bin PyQt5).

В итоге, вопросы:

1 - Что может быть причиной этой разницы в поведении, когда в одном случае я могу загрузить DLL из текущего рабочего каталога, а вВ другом случае я не?

2 - В любом случае, если DLL находится в любом каталоге в PATH, он работает. Может быть, это плохая практика - полагаться на dll в рабочем каталоге и вместо этого устанавливать их где-нибудь правильно?

Спасибо!

1 Ответ

0 голосов
/ 12 октября 2019

Мне удалось выполнить руководство с использованием Process Monitor и фильтрации с помощью:

  • операция CreateFile
  • путь содержит PCANBasic

Я смог увидеть, что у пакета PyInstaller был другой путь поиска, чем у прямой команды.

Затем я обнаружил эту проблему , в которой упоминается, что PyInstaller использует вызов SetDllDirectoryA для добавлениясобственная папка пакета к пути поиска DLL, но с побочным эффектом удаления текущего каталога.

...