12
votes

Is it possible to call a Python function from a C dll function?

We consider this C function:

 void foo( void (*functionPtr)(int,int) , int a, int b);

On Python, I would like to call foo and set the callback to a Python function:

def callback(a, b):
    print("foo has finished its job (%d, %d)" % (a.value,b.value))

dll.foo( callback, c_int(a), c_int(b) )

Unfortunately, the ctypes documentation is pretty light on this topic and the above code does not work.

2
Ctypes callback documentation: docs.python.org/3.3/library/… - Mark Tolonen
The tutorial is often the de facto reference for ctypes, unfortunately. Mark gave you the tutorial link, but surely it's documented enough in the reference section 2.4 to get beyond what you tried: "Function prototypes created by these factory functions can be instantiated in different ways, depending on the type and number of the parameters in the call ... prototype(callable), Create a C callable function (a callback function) from a Python callable". - Eryk Sun

2 Answers

17
votes
import ctypes as c

@c.CFUNCTYPE(None, c.c_int, c.c_int)
def callback(a, b):
    print("foo has finished its job (%d, %d)" % (a.value, b.value))

dll.foo(callback, a, b) # assuming a,b are ints

If you need stdcall calling conventions, use WINFUNCTYPE instead.

Note: if foo may store the callback to be called at a later time then make sure that Python callback is alive (it is enough if it is defined at the global level using the decorator as shown in the example -- modules are essentially immortal in Python unless you try to remove them explicitly).

3
votes

Use CFUNCTYPE to create a callback type:

c_callback = CFUNCTYPE(None, c_int, c_int)(callback)
dll.foo(c_callback, a, b)