question on callback functions with ctypes

oyster lepto.python at gmail.com
Sun Jun 21 01:08:14 EDT 2020


question on callback functions with ctypes

I try to use GoVCL( https://github.com/ying32/govcl ) in python via
ctypes. GoVCL supplies C header and simple C demo under
https://github.com/ying32/govcl/tree/master/Tools/makeCHeader/test

Now the simple python code can run on both win7 and win10 according to
Eryk Sun's suggestion - thank you Eryk Sun. But I am still puzzled by
2 questions

1. the callback function does not been invoked, so there must be
something wrong when I deal with it. However, I can't figure it out.

2. in the original main.c, there is no need to call
`vcl.SetEventCallback(doEventCallbackProc)`. But I learn this in a
python code that uses cffi to call GoVCL. How can I make the python
code as simple as the C code?

Thanks


The following python code is a simplified version of the C code
```python
import sys, os
import ctypes

# In Python 3.8+, ctypes no longer searches PATH or the
# current working directory when loading DLLs.
liblcl_path = os.path.join(os.path.split(os.path.realpath(__file__))[0],
'liblcl.dll')
vcl = ctypes.CDLL(liblcl_path)

def _doEventCallbackProc(f, args, argcount):
    print(f, args, argcount)
    if f == ctypes.addressof(onButton1Click):
        vcl.DShowMessage("Hello world!".encode('utf8'))
    elif f == ctypes.addressof(onFormKeyDown):
        fnOnFormKeyDown(f, args, argcount)
    elif f == ctypes.addressof(onFormKeyDown):
        fnOnFormKeyDown(f, args, argcount)
doEventCallbackProc = ctypes.CFUNCTYPE(ctypes.c_void_p,
ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long)(_doEventCallbackProc)

def _onButton1Click(sender):
    vcl.ShowMessage("Hello world!");
onButton1Click = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(_onButton1Click)
print(ctypes.addressof(onButton1Click))

Char = ctypes.c_uint16
TShiftState = ctypes.c_uint32
def _onFormKeyDown(sender, key, shift):
    print(key, shift);
onFormKeyDown = ctypes.CFUNCTYPE(None, ctypes.c_void_p,
ctypes.POINTER(Char), TShiftState)(_onFormKeyDown)
print(ctypes.addressof(onFormKeyDown))

def _onEditChange(sender):
    print("%s\n", vcl.Edit_GetText(sender));
onEditChange = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(_onEditChange)
print(ctypes.addressof(onEditChange))

def main():
    vcl.SetEventCallback(doEventCallbackProc)

    vcl.Application_Instance.restype = ctypes.c_void_p
    Application = vcl.Application_Instance()

    vcl.Application_Initialize.argtypes = ctypes.c_void_p,
    vcl.Application_Initialize(Application)

    vcl.Application_CreateForm.argtypes = ctypes.c_void_p, ctypes.c_bool
    vcl.Application_CreateForm.restype = ctypes.c_void_p
    form = vcl.Application_CreateForm(Application, False);

    vcl.Form_SetCaption.argtypes = ctypes.c_void_p, ctypes.c_char_p
    vcl.Form_SetCaption(form, "LCL Form".encode('utf8'));

    vcl.Form_SetKeyPreview.argtypes = ctypes.c_void_p, ctypes.c_bool
    vcl.Form_SetKeyPreview(form, True);

    vcl.Form_SetOnKeyDown.argtypes = ctypes.c_void_p,
ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(Char),
TShiftState)
    vcl.Form_SetOnKeyDown(form, onFormKeyDown);

    vcl.Button_Create.argtypes = ctypes.c_void_p,
    vcl.Button_Create.restype = ctypes.c_void_p
    btn = vcl.Button_Create(form);

    vcl.Button_SetParent.argtypes = ctypes.c_void_p, ctypes.c_void_p
    vcl.Button_SetParent(btn, form);

    vcl.Button_SetOnClick.argtypes = ctypes.c_void_p,
ctypes.CFUNCTYPE(None, ctypes.c_void_p)
    vcl.Button_SetOnClick(btn, onButton1Click);

    vcl.Button_SetCaption.argtypes = ctypes.c_void_p, ctypes.c_char_p
    vcl.Button_SetCaption(btn, "button1".encode('utf8'));

    vcl.Button_SetLeft.argtypes = ctypes.c_void_p, ctypes.c_uint32
    vcl.Button_SetLeft(btn, 100);

    vcl.Button_SetTop.argtypes = ctypes.c_void_p, ctypes.c_uint32
    vcl.Button_SetTop(btn, 100);

    vcl.Edit_Create.argtypes = ctypes.c_void_p,
    vcl.Edit_Create.restype = ctypes.c_void_p
    edit = vcl.Edit_Create(form);

    vcl.Edit_SetParent.argtypes = ctypes.c_void_p, ctypes.c_void_p
    vcl.Edit_SetParent(edit, form);

    vcl.Edit_SetOnChange.argtypes = ctypes.c_void_p,
ctypes.CFUNCTYPE(None, ctypes.c_void_p)
    vcl.Edit_SetOnChange(edit, onEditChange);

    vcl.Application_Run.argtypes = ctypes.c_void_p,
    vcl.Application_Run(Application);

main()

```

the C code
```C
#include "liblcl.h"


#ifdef _WIN32
char *UTF8Decode(char* str) {
    int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0);
    wchar_t* wCharBuffer = (wchar_t*)malloc(len * sizeof(wchar_t) + 1);
    MultiByteToWideChar(CP_UTF8, 0, str, -1, wCharBuffer, len);

    len = WideCharToMultiByte(CP_ACP, 0, wCharBuffer, -1, 0, 0, 0, NULL);
    char* aCharBuffer = (char*)malloc(len * sizeof(char) + 1);
    WideCharToMultiByte(CP_ACP, 0, wCharBuffer, -1, aCharBuffer, len, 0, NULL);
    free((void*)wCharBuffer);

    return aCharBuffer;
}
#endif

void onButton1Click(TObject sender) {
    ShowMessage("Hello world!");
}

void onOnDropFiles(TObject sender, void* aFileNames, intptr_t len) {
    printf("aFileNames: %p, len=%d\n", aFileNames, len);
    intptr_t i;
    for (i = 0; i < len; i++) {

#ifdef _WIN32
        char *filename = UTF8Decode(GetStringArrOf(aFileNames, i));
#else
        char *filename = GetStringArrOf(aFileNames, i);
#endif
        printf("file[%d]=%s\n", i+1, filename);
#ifdef _WIN32
        free((void*)filename);
#endif
    }
}

void onFormKeyDown(TObject sender, Char* key, TShiftState shift) {
    printf("key=%d, shift=%d\n", *key, shift);
    if (*key == vkReturn) {
        ShowMessage("press Enter!");
    }

    TShiftState s = Include(0, ssAlt);
    if (InSet(s, ssAlt)) {
        printf("ssAlt1\n");
    }
    s = Exclude(s, ssAlt);
    if (!InSet(s, ssAlt)) {
        printf("ssAlt2\n");
    }
}

void onEditChange(TObject sender) {
    printf("%s\n", Edit_GetText(sender));
}

int main()
{
#ifdef _WIN32
    if (load_liblcl("liblcl.dll")) {
#endif
#ifdef __linux__
    if (load_liblcl("liblcl.so")) {
#endif
#ifdef __APPLE__
    if (load_liblcl("liblcl.dylib")) {
#endif
        Application_Initialize(Application);

        TForm form = Application_CreateForm(Application, FALSE);
        Form_SetCaption(form, "LCL Form");
        Form_SetPosition(form, poScreenCenter);

        Form_SetAllowDropFiles(form, TRUE);
        Form_SetOnDropFiles(form, onOnDropFiles);

        Form_SetKeyPreview(form, TRUE);

        Form_SetOnKeyDown(form, onFormKeyDown);

        TButton btn = Button_Create(form);
        Button_SetParent(btn, form);
        Button_SetOnClick(btn, onButton1Click);
        Button_SetCaption(btn, "button1");
        Button_SetLeft(btn, 100);
        Button_SetTop(btn, 100);

        TEdit edit = Edit_Create(form);
        Edit_SetParent(edit, form);
        Edit_SetLeft(edit, 10);
        Edit_SetTop(edit, 10);
        Edit_SetOnChange(edit, onEditChange);

        Application_Run(Application);

        close_liblcl();
    }
    return 0;
}

```


More information about the Python-list mailing list