Problems using calldll library

David Bolen db3l at fitlinxx.com
Mon Feb 11 20:08:46 EST 2002


picodello at yahoo.it (Piero) writes:

> I need to interface with a windows DLL that is declared in C like:
> 
> getword(&ncard,&nb,&adr,tabl,&status)
> 
> where the type of parameters are :
> 
> ncard=16-bit integer
> nb=16-bit integer
> adr=32-bit integer
> tabl= array of 16-bit integer
> status=16-bit integer
> 
> where ncard,nb,addr are input parameters
> and   tabl,status are output parameters
> 
> I try to implement this function, but don't work.
> I suppose the problem is in the input parameters format.
> Something can help me ?

Do you have any API documentation for the function at hand that
describes the parameters in more detail?

>From the above, I would assume that "tabl" is a pointer to an array of
16-bit integers, but typically one of the other parameters (perhaps
ncard, or nb) would represent - on input - the size of the array, and
possibly - on output - the number of elements returned.

But in your sample code you only allocate enough memory for tabl to
hold a single 16-bit integer, and I also see you putting the supplied
parameters as strings into the memory buffers allocated to ncard and
nb, whereas I would normally expect them to be integer values.  This
could be creating an overrun condition where the function thinks you
have more room in tabl than you really do.

Also, you use "i" in the calldll.call_foreign_function() method for
your references, but I'd probably stick with "l" as a C "long" for a
32-bit pointer.  Each of the parameters is a 32-bit pointer even
though some point to 16-bit integer data.  Then again, I don't know
that any Windows platform currently uses "int" as 16-bit unless you're
using an old 16-bit compiler, so it probably works either way :-)

> 	def getword(self,ncard,nb,adr,tabl):
> 		getword =calldll.get_proc_address(self.applicomdll,"getword")
> 		p = calldll.membuf(4)
> 		px = p.address()
> 		pncard = calldll.membuf(2)
> 		pncard.write(str(ncard))
> 		pxcard = pncard.address()
> 		pnb = calldll.membuf(2)
> 		pnb.write(str(nb))
> 		pxnb = pnb.address()
> 		padr = calldll.membuf(4)
> 		padr.write(str(adr))
> 		pxadr = padr.address()
> 		tabll = calldll.membuf(2)
> 		ptabll = tabll.address()
> 		ret= calldll.call_foreign_function (getword, 'iilii', 'l',
> (pxcard,pxnb,pxadr,ptabll,px))
> 		res = p.read(0, 2)
> 		print struct.unpack('bb', res)[0]
> 		ress = tabll.read(0, 2)
> 		print struct.unpack('bb', ress)[0]

Assuming that ncard, nb, and adr really are numeric, I would at a
minimum suggest changing your function into something like:

    def getword(self,ncard,nb,adr):
	"""Returns tuple (rc, tabl, status)"""

	getword =calldll.get_proc_address(self.applicomdll,"getword")

	# Allocate space for reference parameters and status
	ncard_buf = calldll.membuf(2)
	nb_buf = calldll.membuf(2)
	adr_buf = calldll.membuf(4)
	tabl_buf = calldll.membuf(2 * ncard)     # Assume ncard is count
        status_buf = calldll.membuf(2)

	# Assign initial values
	ncard_buf.write(struct.pack('h',ncard))  # Use 'H' if unsigned
	nb_buf.write(struct.pack('h',nb))        # Use 'H' if unsigned
	adr_buf.write(struct.pack('l',adr))      # Use 'L' if unsigned

	ret = calldll.call_foreign_function (getword, 'lllll', 'l',
                                             ncard_buf.address(),
                                             nb_buf.address(),
                                             adr_buf.address(),
                                             tabl_buf.address(),
                                             status_buf.address())

        status = struct.unpack('h',
                               status_buf.read())[0]   # 'H' = unsigned
	tabl = struct.unpack('%dh'%ncard,
                             tabl_buf.read())[0]       # 'H' = unsigned

        return (ret,status,tabl)

Note that I don't bother with tabl as input since it's an output of
the function, and will be a new list created from the result.  I
suppose you could pass in an existing list to be mutated but it seems
somewhat unnecessary.  Also, I'm assuming that your integer values are
signed.  If they are unsigned make the suggested changes to the
struct.pack/unpack calls.  I also assume 'ncard' was the count of the
size of the array pointed to by tabl, and is unchanged on output.  If
it's really also an output of the function (e.g., the number of
entries returned), then you could unpack ncard_buf and use that rather
than ncard in the unpacking of tabl_buf.

--
-- David
-- 
/-----------------------------------------------------------------------\
 \               David Bolen            \   E-mail: db3l at fitlinxx.com  /
  |             FitLinxx, Inc.            \  Phone: (203) 708-5192    |
 /  860 Canal Street, Stamford, CT  06902   \  Fax: (203) 316-5150     \
\-----------------------------------------------------------------------/



More information about the Python-list mailing list