Re: handling a (python) list to fit in a char** argument

"Mark Tolonen" <[email protected]> Sat, 11 Dec 2010 09:24:50 -0800
Newsgroups gmane.comp.python.ctypes
Message-ID <[email protected]>
"LukenShiro" <[email protected]> wrote in message 
news:[email protected]...
Hello,

I'm developing a LGPL-licensed wrapper to XForms-toolkit, using ctypes
(a wonderful library, indeed!).

A C function to be wrapped has a "char **" argument, so I've
ctypes.POINTER(ctypes.c_char_p) as an .argtypes
In the wrapping python function I think to use a "list of strings",
corresponding to X11-Pixmap (.xpm file) <*> (as you can see it can
have a variable number of elements and each element is a string who can
have a variable number of chars.

I'd use the following function to do a preliminary type check and
to operate a data conversion from one type to another:

§ def convert_to_ptr_string(paramname):
§    """ Converts paramname (list of str) to a ctypes pointer to
c_char_p """
§    if isinstance(paramname, list):     # list of str
§        for idx in range(0, len(paramname)):
§            if not isinstance(paramname[idx], basestring):
§                # every part must be a str
§                .... raise a TypeError .....
§        myarray = (ctypes.c_char_p * len(paramname))()
§        for idx in range(0, len(paramname)):
§            myarray[idx] = ctypes.c_char_p(paramname[idx])
§        retv = ctypes.POINTER(myarray)
§        return retv
§    else:
§        .... raise a TypeError .....

But, when called, I get:

Traceback (most recent call last):
  File "./test_flbitmap.py", line 300, in test_fl_set_pixmap_data_ok
    xfl.fl_set_pixmap_data(self.pxmobj, self.xpmdatalist)
  File "/usr/lib64/python2.6/site-packages/xformslib/flbitmap.py", line
406, in fl_set_pixmap_data
    pxpmdatalist = library.convert_to_ptr_string(xpmdatalist)
  File "/usr/lib64/python2.6/site-packages/xformslib/library.py", line
  266, in convert_to_ptr_string
    retv = cty.POINTER(myarray)
 TypeError: must be a ctypes type

So 'myarray[idx] = cty.c_char_p(paramname[idx])' seems to give the same
result as 'myarray[idx] = paramname[idx]' (same error)

Am I missing anything obvious? How can I resolve this one?

-----------------------

To convert your list of strings array, use:

    def convert_to_ptr_string(paramname):
        return (c_char_p * len(paramname))(*paramname)

and pass the return value of this function directly to your function that 
takes POINTER(c_char_p).

Below is my test code:

---- x.c (compiled with "cl /W4 /LD x.c") ---

#include <stdio.h>

__declspec(dllexport) void func(int argc,char** argv)
{
    int i;
    for(i=0;i<argc;i++)
        printf("argv[%d] = '%s'\n",i,argv[i]);
}

--- x.py ------------

from ctypes import *
func = CDLL('x').func
func.restype = None
func.argtypes = [c_int,POINTER(c_char_p)]

def convert(L):
    return (c_char_p * len(L))(*L)

L = ['abc','defghi','jklmnop']
func(len(L),convert(L))

--- OUTPUT ---

argv[0] = 'abc'
argv[1] = 'defghi'
argv[2] = 'jklmnop'

-Mark



-Mark



------------------------------------------------------------------------------
Oracle to DB2 Conversion Guide: Learn learn about native support for PL/SQL,
new data types, scalar functions, improved concurrency, built-in packages, 
OCI, SQL*Plus, data movement tools, best practices and more.
http://p.sf.net/sfu/oracle-sfdev2dev