C Structure rebuild with ctypes

Mark Tolonen metolone+gmane at gmail.com
Sun Dec 20 18:54:57 EST 2009


"Georg" <nobody at nowhere.org> wrote in message 
news:7p6ksnFkg1U1 at mid.individual.net...
> Hi All,
>
> I need to use a library written in C. The routine  "int func (int handle, 
> int *numVars, char ***varNames, int **varTypes)"
>
> expects a complex object:
>
> " ... Variable names are structured as an array of *numVars pointers, each 
> pointing to a char string containing a variable name, and *varNames is set 
> to point to the first element of the array. Variable types are stored into 
> a corresponding array of *numVars in elements, and *varTypes is set to 
> point to the first element of the array."
>
> I tried using ctypes but nothing worked, e.g. "varNames = (c_char_p(c_char 
> * 65) * NumberOfVariables)()"
>
> Can anyboby help? How do I have to state the structure "array of pointers 
> to char string"? How is a pointer to the first element of such an array 
> defined using ctypes? How do I allocate enough space for the char the 
> array points to?

Are you passing in these values, or are they being returned?  To me the 
depth of the pointer references implies numVars, varNames, and varTypes are 
out parameters. I'll assume that for now.  If they are in/out parameters let 
me know.

I mocked up a DLL to test returning values of these types.  I used VS2008 
and compiled with "cl /LD func.c":

--- func.c -------------------------------
#include <stdlib.h>
#define FUNCDLL
#include "func.h"

static char* g_data[] = {"one","two","three"};
static int g_types[] = {1,2,3};

FUNCAPI int func (int handle, int *numVars, char ***varNames, int 
**varTypes)
{
 *numVars = _countof(g_data);
 *varNames = g_data;
 *varTypes = g_types;
 return handle + 1;
}


--- func.h -------------------------------
#ifdef FUNCDLL
#    define FUNCAPI __declspec(dllexport)
#else
#    define FUNCAPI __declspec(dllimport)
#endif

FUNCAPI int func (int handle, int *numVars, char ***varNames, int 
**varTypes);

--- func.py -------------------------------
import ctypes as c

# shortcuts for useful types
INT = c.c_int
PINT = c.POINTER(INT)
PPINT = c.POINTER(PINT)
PCHAR = c.c_char_p
PPCHAR = c.POINTER(PCHAR)
PPPCHAR = c.POINTER(PPCHAR)

# int func (int handle, int *numVars, char ***varNames, int **varTypes)
func = c.CDLL('func').func
func.restype = INT
func.argtypes = [INT,PINT,PPPCHAR,PPINT]

# allocate storage for the out parameters
numVars = INT()
varNames = PPCHAR()
varTypes = PINT()

print func(5,c.byref(numVars),c.byref(varNames),c.byref(varTypes))

# numVars contains size of returned arrays.  Recast to access.
varNamesArray = c.cast(varNames,c.POINTER(PCHAR * numVars.value))
varTypesArray = c.cast(varTypes,c.POINTER(INT * numVars.value))
for value in varNamesArray.contents:
    print value
for value in varTypesArray.contents:
    print value

--- output -------------------------------
6
one
two
three
1
2
3

Hope this helps,
-Mark





More information about the Python-list mailing list