1. Marcus von Appen
  2. python-utils


python-utils / dll.py

"""DLL wrapper"""
import os
import sys
import warnings
from ctypes import CDLL
from ctypes.util import find_library

__all__ = ["DLL"]

def _findlib(libnames, path=None):
    platform = sys.platform
    if platform in ("win32", "cli"):
        suffix = ".dll"
    elif platform == "darwin":
        suffix = ".dylib"
        suffix = ".so"

    searchfor = libnames
    if type(libnames) is dict:
        # different library names for the platforms
        if platform == "cli" and platform not in libnames:
            # if not explicitly specified, use the Win32 libs for IronPython
            platform = "win32"
        if platform not in libnames:
            platform = "DEFAULT"
        searchfor = libnames[platform]
    results = []
    if path:
        for libname in searchfor:
            dllfile = os.path.join(path, "%s%s" % (libname, suffix))
            if os.path.exists(dllfile):
    for libname in searchfor:
        dllfile = find_library(libname)
        if dllfile:
    return results

class DLL(object):
    """A simple wrapper class for loading shared libraries through ctypes.

    The libinfo argument is a descriptive name of the library, that is
    recommended to be platform neutral, since it is shown to the user on
    errors. libnames can be a list of shared library names or a dictionary
    consisting of platform->library name mappings. path is the explicit library
    path to be used, if any. In case the library is not found in path, ctypes'
    standard mechanism for finding libraries (ctypes.util.find_library) is
    def __init__(self, libinfo, libnames, path=None):
        self._dll = None
        foundlibs = _findlib(libnames, path)
        if len(foundlibs) == 0:
            raise RuntimeError("could not find any library for %s" % libinfo)
        for libfile in foundlibs:
                self._dll = CDLL(libfile)
                self._libfile = libfile
            except Exception as exc:
                # Could not load it, silently ignore that issue and move
                # to the next one.
                warnings.warn(exc, ImportWarning)
        if self._dll is None:
            raise RuntimeError("could not load any library for %s" % libinfo)

    def bind_function(self, funcname, args=None, returns=None, optfunc=None):
        """Binds the passed argument and return value types to the specified
        func = getattr(self._dll, funcname, None)
        if not func:
            func = optfunc
        func.argtypes = args
        func.restype = returns
        return func

    def libfile(self):
        """Gets the filename of the loaded library."""
        return self._libfile

# Example:
# dll = DLL("OpenAL", {"win32": ["OpenAL", "OpenAL32", "soft_oal"],
#                      "darwin": ["OpenAL"],
#                      "DEFAULT": ["openal"]}, os.getenv("OPENAL_DLL_PATH"))
# alGetError = dll.bind_function("alGetError", None, ctypes.c_int)
# ...