17

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.

nowox
  • 25,978
  • 39
  • 143
  • 293
  • 1
    Ctypes callback documentation: https://docs.python.org/3.3/library/ctypes.html?highlight=ctypes#callback-functions – Mark Tolonen Nov 03 '15 at 01:47
  • 1
    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](https://docs.python.org/3.3/library/ctypes.html?highlight=ctypes#function-prototypes) 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 Nov 03 '15 at 02:28

2 Answers2

25
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).

jfs
  • 399,953
  • 195
  • 994
  • 1,670
4

Use CFUNCTYPE to create a callback type:

c_callback = CFUNCTYPE(None, c_int, c_int)(callback)
dll.foo(c_callback, a, b)
nneonneo
  • 171,345
  • 36
  • 312
  • 383