Welcome, guest | Sign In | My Account | Store | Cart
# CLASS NAME: DLLInterface
#
# Author: Larry Bates
#
# Written: 08/14/2002
#
# Description: This is a base class for implementing a class interface
# to call general DLL libraries.  You should build your class using
# this class as the base class.  Define methods for each function of
# the DLL that you wish to implement.
#
import os, sys
import calldll
from dynwin.windll import cstring, membuf

class DLLInterface:
    '''
    class DLLInterface is used as a base class as a general interface class to
    Microsoft Windows DLLs.  None  of the methods of this class should be
    called directly.  Subclass this class and have subclass' methods
    make calls to _dllcall to call functions from the DLL.
    '''

    #--------------------------------------------------------------------------------------------
    # Example usage:
    #
    # class anydll(DLLInterface):
    #    def function1 (self, arg1, arg2, ..., argn)
    #        #
    #        # code goes here to implement function1 from the DLL
    #        # as a method of anydll class.
    #        #
    #        # Syntax of _dllcall function is (function in .DLL,
    #        #                                 argument types,    ['llh' is long, long, short]
    #        #                                 return code type,  ['h' is short]
    #        #                                 arguments in a tuple)              
    #        #
    #        result=self._dllcall('function1',
    #                             'lll',
    #                             'h',
    #                             (arg1,
    #                              arg2,
    #                              arg3,
    #                               .
    #                               .
    #                               .
    #                              argn))
    #        return result
    #
    # this would then be executed using:
    #
    # D=anydll(DLLPath)
    # result=d.function(arg1, arg2, ..., argn)
    #
    # argument types = 'h'-short, 'l'-long, 's'-string (null terminated using helper function
    #                                                   cstring in dynwin)
    #--------------------------------------------------------------------------------------------
       
    def __init__(self, DLLPath, ext='.dll'):
        self._debug=0
        self._trace=0
        self._loaded=0
        self._funcs={}
        self._DLLName=os.path.split(DLLPath)[1]+ext  # Save DLL filename
        if self._trace: print "creating _handle"
        #
        # Load the DLL library (if not already loaded) and save a
        # handle to it in self._handle
        #
        if not self._loaded:
            self._handle=calldll.load_library(DLLPath+ext)
            #
            # If I didn't get a handle, DLL wasn't loaded
            #
            if not self._handle:
                raise SystemError, "couldn't load module '%s'" % self._DLLName
            else:
                self._loaded=1
            
        if self._trace: print "handle=",self._handle

        if self._trace: print "Leaving __init__"
        return

    def unload(self):
        if self._loaded and self._handle:
            calldll.free_library(self._handle)
            
        self._loaded=0
        self._handle=0
        self._funcs={}
        return

    def _dlladdr(self, func_name):
        #
        # This method uses the function name (func_name) and looks into the .DLL
        # to find the address that should be used to call that function.
        #
        if self._trace: print "self._handle=",self._handle
        if self._trace: print "_dlladdr to get address of %s func" % func_name
        if not self._handle:
            raise SystemError, "No handle found for %s" % self._DLLName
        #
        # See if I've called this func_name before.  If I have, I have saved
        # the address in self._funcs dictionary object so I don't have to call
        # calldll.get_proc_address repeatedly.  A method of "caching" the addresses.
        # to hopefully speed things up a little.
        #
        try:
            addr=self._funcs[func_name]
        except:
            addr=calldll.get_proc_address(self._handle, func_name)
            self._funcs[func_name]=addr
            
        if self._trace:
            print "leaving _dlladdr, function %s has calling address=%i" % (func_name, addr)
            print ""
        #
        # Return the address of this function so it can be called by calldll
        #
        if addr: return addr
        else:    raise SystemError, "%s has no function named '%s'" % (self._DLLName, func_name)

    def _dllcall(self, function_name,arg_format_string, result_format_string, args):
        #
        # This method is used to make the call to the DLL function
        # Arguments are:
        #
        # function_name - String containing the name of the function to call
        # arg_format_string - this is a string that contains the format of the
        #                     arguments that are to be passed to the function.
        #                     These can be one of:
        #                     l - long integer (or address)
        #                     h - short integer (half)
        #                     s - string
        #
        #                     Example: "lllh"
        #
        # result_format_string - The result will be either l or h, returned by
        #                        function
        # args - This is a tuple (even if there is only one argument)
        #
        #                     Example: (x,) or (a,b,c,d)
        #
        if self._trace: print "Entering _dllcall to call function=",function_name
        result=calldll.call_foreign_function(self._dlladdr(function_name),
                                                           arg_format_string,
                                                           result_format_string,
                                                           args)
        #
        # If result_format_string is "h" mask out high bits of result
        #
        if result_format_string in ('h','H'):
            result=result & 0xffff
            
        #
        # If result_format_string is "s", strip off trailing null character
        #
        if result_format_string in ('s','S'):
            result=result[:-1]

        return result          

History