Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] - نسخه متنی

David Ascher, Alex Martelli, Anna Ravenscroft

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


Recipe 17.4. Calling Functions from a Windows DLL


Credit: Stefano Spinucci


Problem


You want to avoid writing a Python
extension in C, by directly calling from Python functions that
already exist in a Windows DLL.


Solution


The third-party ctypes extension makes this task
pretty easy:

from ctypes import windll, c_int, c_string, byref
# load 'Ehllapi.dll' (from current dir),
and function 'hllapi' from the DLL
Ehllap32 = windll.ehllapi
hllapi = Ehllap32.hllapi
# prepare the arguments with types and initial values
h_func = c_int(1)
h_text = c_string('A')
h_len = c_int(1)
h_ret = c_int(999)
# call the function
hllapi(byref(h_func), h_text, byref(h_len), byref(h_ret))
# print the resulting values of all arguments after the call
print h_func.value, h_text.value, h_len.value, h_ret.value


Discussion


I needed the code in this recipe specifically to call a C function
whose prototype is:

void FAR PASCAL hllapi(int FAR *, char FAR *, int FAR *, int FAR *);

from a DLL named Ehllapi.DLL (an implementation
of the IBM 3270 HLLAPI for an Italian 3270 terminal emulator, as it
happens). Thomas Heller's ctypes
extension, found at http://sourceforge.net/projects/ctypes, made
the task very easy. In particular, ctypes makes
mincemeat of problems related to representing function arguments that
must belong to a certain C type and possibly get passed
"by reference" (i.e., via a
pointer).

In the past, I used another extension, known as
calldll, which was (and still is) available from
http://www.nightmare.com/softwarel. While
once very useful, calldll cannot rely on some of
the modern techniques that ctypes uses internally,
because these possibilities were introduced only in relatively recent
versions of Python. calldll, using a single
membuf Python type to represent all possible C
types, tends to be much more cumbersome than
ctypes when they are both used to perform the same
tasks.

Judge for yourself: here is a working calldll
version of the same script that I just showed how to code with
ctypes:

import calldll, struct
# some helpful auxiliary functions
def myPrintLong(vVar):
''' print a long contained in a membuf '''
print calldll.read_long(vVar.address( ))
def myPrintString(vVar):
''' print a string contained in a membuf '''
a = calldll.read_string(vVar.address( ))
print a, len(a)
def mySetLong(vMemBuf, vValueToSet):
''' set to an unsigned long the value of a membuf with len == 4 '''
vMemBuf.write(struct.pack('L', vValueToSet))
def mySetString(vMemBuf, vValueToSet):
''' set to a string (with \0 terminator) the value of a membuf '''
pack_format = "%ds" % 1+len(vValueToSet)# +1 for the \0
string_packed = struct.pack(pack_format, vValueToSet)
# pack( ) adds the \0
vMemBuf.write(string_packed)
# load 'Ehllapi.dll' (from current dir),
and function 'hllapi' from the DLL
dll_handle = calldll.load_library ('.\\Ehllapi')
function_address = calldll.get_proc_address (dll_handle, 'HLLAPI')
# allocate and init three membufs with the size
to hold an unsigned long
Lsize = struct.calcsize('L')
vFunction = calldll.membuf(Lsize)
mySetLong(vFunction, 1)
vTextLen = calldll.membuf(Lsize)
vResult = calldll.membuf(Lsize)
mySetLong(vResult, 1)
# allocate a membuf as large as the DLL requires;
in this case, space
# for 24 x 80 characters + 1 for a \0 terminator
vText = calldll.membuf(1921)
# init the text and text-length variables based on string of interest
string_value_to_write = 'A'
mySetString(vText, string_value_to_write)
mySetLong(vTextLen, len(string_value_to_write))
# call the function, print the results, and clean up
calldll.call_foreign_function(function_address, 'llll', 'l',
(vFunction.address( ), vText.address( ),
vTextLen.address( ), vResult.address( )))
myPrintLong(vResult)
myPrintString(vText)
calldll.free_library(dll_handle)

To be honest, I can't quite be sure whether all of
these gyrations are truly indispensable to making this
calldll-based version work. Whenever I try to
simplify this version a bit, something or other always breaks
noisily, so I've stopped messing with it. One reason
the ctypes-based version is cleaner and simpler is
that ctypes has never given me trouble, so
I've been encouraged to continue working on that
version to improve it.


See Also


ctypes is at http://sourceforge.net/projects/ctypes;
calldll is at http://www.nightmare.com/softwarel.

/ 394