What is the correct callback signature for a function called using ctypes in python?
Question: I have to define a callback function in Python, one that will be called from a
DLL.

    
    
    BOOL setCallback (LONG nPort, void ( _stdcall *pFileRefDone) (DWORD nPort, DWORD nUser), DWORD nUser);
    

I tried this code, that seems to work in Python 2.5 but with Python 2.7 it
crashes and I assume I did something wrong.

    
    
    import ctypes, ctypes.wintypes
    from ctypes.wintypes import DWORD
    
    def cbFunc(port, user_data):
            print "Hurrah!"
    
    CB_Func = ctypes.WINFUNCTYPE(None, DWORD, DWORD)
    
    mydll.setCallback(ctypes.c_long(0), CB_Func(cbFunc), DWORD(0))
    

Where is the mistake?

Note: The platform is running on 32bit only (both Windows and Python). The DLL
loads successfully and also other functions from inside do work just fine
while called from Python.

A full sample code that reproduces this is available at
<https://github.com/ssbarnea/pyHikvision> \- just run Video.py under py25 and
py27.


Answer: Your CB_Func(cbFunc) parameter gets garbage-collected right after the
setCallback function. That object has to persist as long as the callback can
be called ([15.17.1.17. Callback
functions](http://docs.python.org/library/ctypes.html?highlight=ctypes#callback-
functions), last paragraph). Assign it to a variable and keep it around.
Here's my working example:

### DLL

    
    
    typedef unsigned int DWORD;
    typedef long LONG;
    typedef int BOOL;
    #define TRUE  1
    #define FALSE 0
    
    typedef void (__stdcall *CALLBACK)(DWORD,DWORD);
    
    CALLBACK g_callback = 0;
    DWORD g_port = 0;
    DWORD g_user = 0;
    
    BOOL __declspec(dllexport) setCallback (LONG nPort, CALLBACK callback, DWORD nUser)
    {
        g_callback = callback;
        g_port = nPort;
        g_user = nUser;
        return TRUE;
    }
    
    void __declspec(dllexport) Fire()
    {
        if(g_callback)
            g_callback(g_port,g_user);
    }
    

### Failing Script

    
    
    from ctypes import *
    
    def cb_func(port,user):
        print port,user
    
    x = CDLL('x')
    CALLBACK = WINFUNCTYPE(None,c_uint,c_uint)
    #cbfunc = CALLBACK(cb_func)
    x.setCallback(1,CALLBACK(cb_func),2)
    x.Fire()
    

### Passing Script

    
    
    from ctypes import *
    
    def cb_func(port,user):
        print port,user
    
    x = CDLL('x')
    CALLBACK = WINFUNCTYPE(None,c_uint,c_uint)
    cbfunc = CALLBACK(cb_func)
    x.setCallback(1,cbfunc,2)
    x.Fire()
    

**Edit** : Also, since `CALLBACK` is a function returning a function, it can
be used as a decorator for the Python callback, eliminating problem of the
callback going out of scope:

    
    
    from ctypes import * 
    
    CALLBACK = WINFUNCTYPE(None,c_uint,c_uint) 
    
    @CALLBACK
    def cb_func(port,user): 
        print port,user 
    
    x = CDLL('x') 
    x.setCallback(1,cb_func,2) 
    x.Fire() 
    

