Need help calling a proprietary C DLL from Python

Craig craigm3604 at gmail.com
Sat Mar 22 18:12:47 EDT 2008


On Mar 22, 3:13 pm, Dennis Lee Bieber <wlfr... at ix.netcom.com> wrote:
> On Fri, 21 Mar 2008 23:21:48 -0700 (PDT), Craig <craigm3... at gmail.com>
> declaimed the following in comp.lang.python:
>
> > Sorry, I wasn't trying to exclude any credit from Dennis, I just
> > wasn't sure if he wanted to be listed.
>
>         As responded to elsewhere -- it was more a case of minimizing the
> "non-work" traffic on my work email address...
>
>         <snip>
>
> > This is what I have tried:
>
>         <snip>
>
> > LPBSTR = POINTER(c_void_p)
>
>         <snip>
>
> > And, on the last variation of this, this function needs to receive
> > BSTR values passed back from the dll:
> > short FAR PASCAL VmxGet(LPHANDLE lpDatasetNumber, LPSHORT lpSecIndex,
> >                         LPSHORT lpOption, BSTR *SrchKey,
> >                         BSTR  *SecKey, BSTR  *PriKey, LPSTR
> > lpTypeDef);
> > SrchKey is provided by me, SecKey and PriKey are returned by the dll,
> > and TypeDef is defined by me and filled by the dll.
>
> > For this, I have added:
> > VmxGet = windll.vbis5032.VmxGet
> > VmxGet.restype = c_short
> > VmxGet.argtypes = [LPHANDLE, LPSHORT, LPSHORT, LPBSTR, LPBSTR, LPBSTR,
> > LPBSTR]
>
>         Remember that Python strings are immutable... Also note that the
> signature you give above seems to differentiate between passing a
> pointer variable LPSTR (ie; lpTypeDef is just 4-bytes which will/should
> contain the address pointing to the real string) and passing the address
> of the first byte of a string buffer BSTR (*PriKey is the same as
> &PriKey[0] -- but PriKey itself has to be a sequence of characters or an
> empty buffer allocated to hold them).
>
> From the ctypes documentation:
>        http://docs.python.org/lib/node453.html
>
> """
> Assigning a new value to instances of the pointer types c_char_p,
> c_wchar_p, and c_void_p changes the memory location they point to, not
> the contents of the memory block (of course not, because Python strings
> are immutable):
>
> >>> s = "Hello, World"
> >>> c_s = c_char_p(s)
> >>> print c_s
>
> c_char_p('Hello, World')>>> c_s.value = "Hi, there"
> >>> print c_s
>
> c_char_p('Hi, there')
>
> >>> print s                 # first string is unchanged
> Hello, World
>
> You should be careful, however, not to pass them to functions expecting
> pointers to mutable memory. If you need mutable memory blocks, ctypes
> has a create_string_buffer function which creates these in various ways.
> The current memory block contents can be accessed (or changed) with the
> raw property; if you want to access it as NUL terminated string, use the
> value property:
>
> >>> from ctypes import *
> >>> p = create_string_buffer(3)      # create a 3 byte buffer, initialized to NUL bytes
> >>> print sizeof(p), repr(p.raw)
> 3 '\x00\x00\x00'
> >>> p = create_string_buffer("Hello")      # create a buffer containing a NUL terminated string
> >>> print sizeof(p), repr(p.raw)
> 6 'Hello\x00'
> >>> print repr(p.value)
> 'Hello'
> >>> p = create_string_buffer("Hello", 10)  # create a 10 byte buffer
> >>> print sizeof(p), repr(p.raw)
>
> 10 'Hello\x00\x00\x00\x00\x00'>>> p.value = "Hi"
> >>> print sizeof(p), repr(p.raw)
>
> 10 'Hi\x00lo\x00\x00\x00\x00\x00'
>
> """
>
>         Drawback -- it looks like you may have to preset the size of the
> buffer...
>
> --
>         Wulfraed        Dennis Lee Bieber               KD6MOG
>         wlfr... at ix.netcom.com             wulfr... at bestiaria.com
>                 HTTP://wlfraed.home.netcom.com/
>         (Bestiaria Support Staff:               web-a... at bestiaria.com)
>                 HTTP://www.bestiaria.com/


That is not really a drawback. Pretty much everything is fixed-length
anyway.

I guess I am having trouble with the whole immutable thing.

And, the pointers too.

Anyway, I have the following for "types":
LPBSTR = POINTER(c_void_p)
HANDLE = POINTER(POINTER(c_long))
LPHANDLE = POINTER(HANDLE)
LPSHORT = POINTER(c_short)
LPVSTATS = POINTER(c_void_p)
c_string = c_char_p
LPSTR = c_string

I guess passing a structure is out of the question. So, I tried a
string (something - just to get the data back):
#short FAR PASCAL VmxInfo(LPHANDLE lpDatasetNumber, LPVSTATS
lpvstats);
VmxInfo = windll.vbis5032.VmxInfo
VmxInfo.restype = c_short
VmxInfo.argtypes = [LPHANDLE, LPSTR]
VsamInfo = create_string_buffer("12345678901234567890123456789012")
printf ("VsamInfo = \x22%s\x22\n", VsamInfo.raw)
print "Ready to call (Library = " + find_library("vbis5032") + ") ..."
res = VmxInfo( byref(hwmcb), byref(VsamInfo) )
And I get:
Ready to call (Library = C:\Windows\vbis5032.dll) ...
Traceback (most recent call last):
  File "C:\temp\vbisam_test_2.py", line 101, in <module>
    res = VmxInfo( byref(hwmcb), byref(VsamInfo) )
ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: wrong
type


So, to get to the VmxGet, I comment out the VmxInfo call, and proceed
to:
SrchKey =
windll.oleaut32.SysAllocStringByteLen("MSD19PH
\x00", 41)
SecKey =
windll.oleaut32.SysAllocStringByteLen("1234567890123456789012345678901234567890\x00",
41)
PriKey =
windll.oleaut32.SysAllocStringByteLen("1234567890123456789012345678901234567890\x00",
41)
TypeDef = create_string_buffer("X".center(129, "X"))
print "Ready to call (Library = " + find_library("vbis5032") + ") ..."
res = VmxGet( byref(hwmcb), byref(SecIndex), byref(Option),
byref(c_void_p(SrchKey)), byref(c_void_p(SecKey)),
byref(c_void_p(PriKey)), byref(c_void_p(TypeDef)) )
And for this, I get:
Ready to call (Library = C:\Windows\vbis5032.dll) ...
Traceback (most recent call last):
  File "C:\temp\vbisam_test_2.py", line 114, in <module>
    res = VmxGet( byref(hwmcb), byref(SecIndex), byref(Option),
byref(c_void_p(S
rchKey)), byref(c_void_p(SecKey)), byref(c_void_p(PriKey)),
byref(TypeDef) )
ctypes.ArgumentError: argument 7: <type 'exceptions.TypeError'>: wrong
type


I know I am missing something, probably very basic (pardon the pun) to
Python.




More information about the Python-list mailing list