#-----------------------------------------------------------------------------
|
# Copyright (c) 2005-2023, PyInstaller Development Team.
|
#
|
# Distributed under the terms of the GNU General Public License with exception
|
# for distributing bootloader.
|
#
|
# The full license is in the file COPYING.txt, distributed with this software.
|
#-----------------------------------------------------------------------------
|
"""
|
Hooks to make ctypes.CDLL, .PyDLL, etc. look in sys._MEIPASS first.
|
"""
|
|
import sys
|
|
|
def install():
|
"""
|
Install the hooks.
|
|
This must be done from a function as opposed to at module-level, because when the module is imported/executed,
|
the import machinery is not completely set up yet.
|
"""
|
|
import os
|
|
try:
|
import ctypes
|
except ImportError:
|
# ctypes is not included in the frozen application
|
return
|
|
def _frozen_name(name):
|
# If the given (file)name does not exist, fall back to searching for its basename in sys._MEIPASS, where
|
# PyInstaller usually collects shared libraries.
|
if name and not os.path.isfile(name):
|
frozen_name = os.path.join(sys._MEIPASS, os.path.basename(name))
|
if os.path.isfile(frozen_name):
|
name = frozen_name
|
return name
|
|
class PyInstallerImportError(OSError):
|
def __init__(self, name):
|
self.msg = (
|
"Failed to load dynlib/dll %r. Most likely this dynlib/dll was not found when the application "
|
"was frozen." % name
|
)
|
self.args = (self.msg,)
|
|
class PyInstallerCDLL(ctypes.CDLL):
|
def __init__(self, name, *args, **kwargs):
|
name = _frozen_name(name)
|
try:
|
super().__init__(name, *args, **kwargs)
|
except Exception as base_error:
|
raise PyInstallerImportError(name) from base_error
|
|
ctypes.CDLL = PyInstallerCDLL
|
ctypes.cdll = ctypes.LibraryLoader(PyInstallerCDLL)
|
|
class PyInstallerPyDLL(ctypes.PyDLL):
|
def __init__(self, name, *args, **kwargs):
|
name = _frozen_name(name)
|
try:
|
super().__init__(name, *args, **kwargs)
|
except Exception as base_error:
|
raise PyInstallerImportError(name) from base_error
|
|
ctypes.PyDLL = PyInstallerPyDLL
|
ctypes.pydll = ctypes.LibraryLoader(PyInstallerPyDLL)
|
|
if sys.platform.startswith('win'):
|
|
class PyInstallerWinDLL(ctypes.WinDLL):
|
def __init__(self, name, *args, **kwargs):
|
name = _frozen_name(name)
|
try:
|
super().__init__(name, *args, **kwargs)
|
except Exception as base_error:
|
raise PyInstallerImportError(name) from base_error
|
|
ctypes.WinDLL = PyInstallerWinDLL
|
ctypes.windll = ctypes.LibraryLoader(PyInstallerWinDLL)
|
|
class PyInstallerOleDLL(ctypes.OleDLL):
|
def __init__(self, name, *args, **kwargs):
|
name = _frozen_name(name)
|
try:
|
super().__init__(name, *args, **kwargs)
|
except Exception as base_error:
|
raise PyInstallerImportError(name) from base_error
|
|
ctypes.OleDLL = PyInstallerOleDLL
|
ctypes.oledll = ctypes.LibraryLoader(PyInstallerOleDLL)
|
|
try:
|
import ctypes.util
|
except ImportError:
|
# ctypes.util is not included in the frozen application
|
return
|
|
# Same implementation as ctypes.util.find_library, except it prepends sys._MEIPASS to the search directories.
|
def pyinstaller_find_library(name):
|
if name in ('c', 'm'):
|
return ctypes.util.find_msvcrt()
|
# See MSDN for the REAL search order.
|
search_dirs = [sys._MEIPASS] + os.environ['PATH'].split(os.pathsep)
|
for directory in search_dirs:
|
fname = os.path.join(directory, name)
|
if os.path.isfile(fname):
|
return fname
|
if fname.lower().endswith(".dll"):
|
continue
|
fname = fname + ".dll"
|
if os.path.isfile(fname):
|
return fname
|
return None
|
|
ctypes.util.find_library = pyinstaller_find_library
|
|
|
# On Mac OS insert sys._MEIPASS in the first position of the list of paths that ctypes uses to search for libraries.
|
#
|
# Note: 'ctypes' module will NOT be bundled with every app because code in this module is not scanned for module
|
# dependencies. It is safe to wrap 'ctypes' module into 'try/except ImportError' block.
|
if sys.platform.startswith('darwin'):
|
try:
|
from ctypes.macholib import dyld
|
dyld.DEFAULT_LIBRARY_FALLBACK.insert(0, sys._MEIPASS)
|
except ImportError:
|
# Do nothing when module 'ctypes' is not available.
|
pass
|