Python Forum
use NULL as function parameter which is a pointer function? - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: use NULL as function parameter which is a pointer function? (/thread-28254.html)



use NULL as function parameter which is a pointer function? - oyster - Jul-11-2020

Hi, I met a case in which NULL can be used as a C function's parameter which is actually a pointer function. I can't finger out how to do it, can anyone help. Thanks

1. the case

The C function in [LCUI](https://github.com/lc-soft/LCUI) is defined as
typedef void(*LCUI_WidgetEventFunc)(LCUI_Widget, LCUI_WidgetEvent, void*);

LCUI_API int Widget_BindEvent(LCUI_Widget widget, const char *event_name,
        LCUI_WidgetEventFunc func, void *data,
        void(*destroy_data)(void*));
which is called in [helloworld](https://github.com/lc-soft/LCUI/blob/develop/test/helloworld.c#L31) as

static void OnBtnClick(LCUI_Widget self, LCUI_WidgetEvent e, void *arg){
	do something();    
}

Widget_BindEvent(btn, "click", OnBtnClick, NULL, NULL);
Then I try to translate it into python

2. the 1st attempt

LCUI_WidgetEventFunc = ctypes.CFUNCTYPE(None, LCUI_Widget, LCUI_WidgetEvent, ctypes.c_void_p)

_Widget_BindEvent = dll.Widget_BindEvent
#~ _Widget_BindEvent.argtypes = LCUI_Widget, ctypes.c_char_p, LCUI_WidgetEventFunc, ctypes.c_void_p, ctypes.c_void_p
def Widget_BindEvent( widget, event_name, func, data, destroy_data,):
    event_name = event_name.encode('utf8')
    func = LCUI_WidgetEventFunc(func)

    return _Widget_BindEvent( widget, event_name, func, data, destroy_data)
then I call it as

def OnBtnClick(self, e, arg):
    do something()
    
Widget_BindEvent( btn, "click", LCUI_WidgetEventFunc(OnBtnClick), 
	None,
	ctypes.cast(None, ctypes.CFUNCTYPE(None, ctypes.c_void_p))
    );
But python fails to run this code and says
Output:
Traceback (most recent call last): File "helloworld.py", line 60, in <module> main() File "helloworld.py", line 54, in main ctypes.cast(None, ctypes.CFUNCTYPE(None, ctypes.c_void_p)) File "r:\lc\LCUI.py", line 88, in Widget_BindEvent destroy_data OSError: exception: access violation reading 0x0000000000000270
3. the 2nd try

_Widget_BindEvent = dll.Widget_BindEvent

prototype = ctypes.CFUNCTYPE(ctypes.c_int,
	LCUI_Widget,
	ctypes.c_char_p,
	LCUI_WidgetEventFunc,
	ctypes.c_void_p,
	ctypes.CFUNCTYPE(None, ctypes.c_void_p)
)

Widget_BindEvent = prototype(_Widget_BindEvent)

Widget_BindEvent( btn,
    "click".encode(),
    LCUI_WidgetEventFunc(OnBtnClick),
    None,
    ctypes.cast(None, ctypes.CFUNCTYPE(None, ctypes.c_void_p))
);
this time python runs the code but says

Output:
Traceback (most recent call last): File "_ctypes/callbacks.c", line 234, in 'calling callback function' OSError: exception: access violation reading 0x0000000000000270
So what is the proper way to wrap Widget_BindEvent so that we can use real function or NULL in it?