функция обратного вызова в python ctypes говорит "ctypes.ArgumentError" - PullRequest
0 голосов
/ 10 июля 2020

В helloworld. c он пишет

Widget_BindEvent(btn, "click", OnBtnClick, NULL, NULL);

И я обнаружил, что прототип Widget_BindEvent определен в widget_event.h как

LCUI_API int Widget_BindEventById(LCUI_Widget widget, int event_id,
                  LCUI_WidgetEventFunc func, void *data,
                  void(*destroy_data)(void*));

, где LCUI_WidgetEventFunc определено в widget_event.h как

typedef void(*LCUI_WidgetEventFunc)(LCUI_Widget, LCUI_WidgetEvent, void*);

Поэтому я перевожу код в


class LCUI_WidgetEventRec_ (ctypes.Structure): pass
LCUI_WidgetEvent = ctypes.POINTER(LCUI_WidgetEventRec_)

LCUI_WidgetEventFunc = ctypes.CFUNCTYPE(ctypes.c_void_p, 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=None, destroy_data=None ):
    event_name = event_name.encode('utf8')
    func = LCUI_WidgetEventFunc(func)
    data = ctypes.cast(data, ctypes.c_void_p),
    destroy_data = ctypes.cast(destroy_data, ctypes.c_void_p)

    return _Widget_BindEvent( widget, event_name, func, data, destroy_data )

Затем Я называю это

Widget_BindEvent(btn, "click", OnBtnClick, None, None);

Но я получаю

  File "helloworld.py", line 24, in main
    Widget_BindEvent(btn, "click", OnBtnClick, None, None);
  File "r:\LC-Finder\app\LCUI.py", line 82, in Widget_BindEvent
    destroy_data
ctypes.ArgumentError: argument 4: <class 'TypeError'>: wrong type

Очевидно, что часть функции обратного вызова неверна. Любая помощь? Спасибо

ps 1, LCUI.dll можно найти в LC-Finder.zip из https://github.com/lc-soft/LC-Finder/releases. который предназначен только для windows. Но говорят, что версию linux можно легко скомпилировать.

ps 2, полный код

# helloworld.py
from LCUI import *

def OnBtnClick(self: LCUI_Widget, e: LCUI_WidgetEvent, arg):
    str = ctypes.c_wchar*256
    edit = LCUIWidget_GetById("edit");
    txt = LCUIWidget_GetById("text-hello");

    TextEdit_GetTextW(edit, 0, 255, str);
    TextView_SetTextW(txt, str);


def main():
    LCUI_Init();
    root = LCUIWidget_GetRoot();
    pack = LCUIBuilder_LoadFile("helloworld.xml".encode('utf8'));
    if (not pack):
        return -1;

    Widget_Append( root, pack,);

    Widget_Unwrap(pack);

    btn = LCUIWidget_GetById("btn");
    Widget_BindEvent(btn, "click", OnBtnClick, None, None);

    return LCUI_Main();

if __name__ == '__main__':
    main()

и

# LCUI.py
import ctypes

NULL = 0

dll = ctypes.CDLL('lcui.dll')

class LCUI_WidgetRec_ (ctypes.Structure): pass
LCUI_Widget =ctypes.POINTER(LCUI_WidgetRec_)

LCUI_Init = dll.LCUI_Init

LCUIWidget_GetRoot = dll.LCUIWidget_GetRoot
LCUIWidget_GetRoot.restype = LCUI_Widget

LCUIBuilder_LoadFile = dll.LCUIBuilder_LoadFile
LCUIBuilder_LoadFile.restype = LCUI_Widget

Widget_Append = dll.Widget_Append
Widget_Append.argtypes = LCUI_Widget, LCUI_Widget
Widget_Append.restype = ctypes.c_int

Widget_Unwrap = dll.Widget_Unwrap

LCUIWidget_GetById = dll.LCUIWidget_GetById
LCUIWidget_GetById.restype = LCUI_Widget

class LCUI_WidgetEventRec_ (ctypes.Structure):    pass
LCUI_WidgetEvent = ctypes.POINTER(LCUI_WidgetEventRec_)

LCUI_WidgetEventFunc = ctypes.CFUNCTYPE(ctypes.c_void_p, 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=None, destroy_data=None):
    event_name = event_name.encode('utf8')
    func = LCUI_WidgetEventFunc(func)
    data = ctypes.cast(data, ctypes.c_void_p),
    destroy_data = ctypes.cast(destroy_data, ctypes.c_void_p)

    return _Widget_BindEvent( widget, event_name, func, data, destroy_data )

LCUI_Main = dll.LCUI_Main
...