[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

question on callback functions with ctypes

question on callback functions with ctypes

I try to use GoVCL( ) in python via
ctypes. GoVCL supplies C header and simple C demo under

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?


The following python code is a simplified version of the C code
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],
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)

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)

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

def main():

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

    vcl.Application_Initialize.argtypes = ctypes.c_void_p,

    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),
    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,



the C code
#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);

    return aCharBuffer;

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));
        char *filename = GetStringArrOf(aFileNames, i);
        printf("file[%d]=%s\n", i+1, filename);
#ifdef _WIN32

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)) {
    s = Exclude(s, ssAlt);
    if (!InSet(s, ssAlt)) {

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

int main()
#ifdef _WIN32
    if (load_liblcl("liblcl.dll")) {
#ifdef __linux__
    if (load_liblcl("")) {
#ifdef __APPLE__
    if (load_liblcl("liblcl.dylib")) {

        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);


    return 0;