Issue with ctypes and callback functions

Bill Somerville BSomerville at flexerasoftware.com
Wed Aug 3 09:21:08 EDT 2016


-----Original Message-----
From: eryk sun [mailto:eryksun at gmail.com] 
Sent: 03 August 2016 13:16
To: python-list at python.org
Cc: Bill Somerville <BSomerville at flexerasoftware.com>
Subject: Re: Issue with ctypes and callback functions

On Wed, Aug 3, 2016 at 9:38 AM, Bill Somerville <BSomerville at flexerasoftware.com> wrote:
>
> Is this a good place to ask questions about the above?

Discussing ctypes is fine here. There's also a ctypes-users list.


Thanks Eryk,

I am trying to handle Python callback functions in a SWIG interface, SWIG does not support callbacks where the target is a Python callable but I can do this with ctypes. My problem is that I need to have the callback receive a SWIG wrapped type as an argument by reference. I see that if I use a ctypes.Structure type then it works nicely but I have a huge and changing API to wrap and do not want to manually describe every C struct with ctypes.Structure when SWIG has already automatically created its own shadow classes. The SWIG struct wrapper is just a class wrapping a pointer so can be easily be passed just like ctypes.Structure can be. How do I tell ctypes that it needs to reconstitute the type from an address in the callback thunk it generates?

I have tried defining from_param() and self._as_parameter_ for the types which works for passing to a function but I don't need that as SWIG does that already. With callback arguments I get various errors depending on what methods/attributes I supply like:

Parsing argument 0
TypeError: cannot build parameter

At the point where the callback is being called.

To summarize:
++++++++++++++++++++++++++++++++++++
C API like:

typedef struct {
    int member;
    /* ... */
} my_type;
typedef int (*pfn) (my_type const *);
int fn (pfn);

Implementation could be:

#include "api.h"
int fn (pfn cb) {
    my_type t = {42, /* ... */};
    return cb (&t);
}

I want Python code like:

from ctypes import *
import api  # SWIG extension module

def my_cb (t):
    print ('in callback with:', t.member)
    return 0

proto = CFUNCTYPE (c_int, my_type)
cb = proto (my_cb)
res = api.fn (cast (cb, c_void_p).value)
print ('fn returned:', res)

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

I can extend the SWIG shadow class to do the creation of the prototype and thunk, the required cast above and any extra attributes or methods like _as_parameter_ and from_param() but I can't see any way of having the Python callback (my_cb) magically receive the SWIG wrapped 'my_type' struct.

TIA
Bill.


More information about the Python-list mailing list