Cython is slower than ctypes in win32 based gui

13 views
Skip to first unread message

vinod kc

unread,
Feb 12, 2026, 11:27:08 AM (yesterday) Feb 12
to cython-users
Hi all,
I have created a gui library in C3 with win32 api. Compiled it as a dll and called the functions in that dll from python via ctypes. Then I created a cython file to call the same dll functions. Then I tested both projects. The ctypes version ran faster than cython version. Ctypes version took 7.3 ms to display the window but cython version took 8.15 ms. This was a surprise to me. Do I need to tweak anything in cython to improve the performance ? 
In Cython my current approach to pass the wchar ptr to dll was,
1. Create a common wchar buffer with PyMem_Alloc (module level cdef variable)
2. Use PyUnicode_AsWideChar to fill the buffer
3. Pass the buffer address to dll. 

But in ctypes, I have,
1. Created an instance of ctypes.c_wchar_p with python string so that I can use the internal string buffer of python.
2. Keep the instance available until win32 api finished it's job with that string.

da-woods

unread,
Feb 12, 2026, 4:45:46 PM (23 hours ago) Feb 12
to cython...@googlegroups.com

I'm not quite sure I understand your ctypes approach perfectly. But I think the difference is: in the Cython version you convert the strings on every function call. In the ctypes version you convert the strings once with `ctypes.c_wchar_p` and then pass the existing object to each function call.

Potentially you could do the same thing in Cython. The easiest way to convert a string to a wchar buffer Python object is probably `array.array('H', s.encode('utf_16'))` or `memoryview(s.encode('utf_16')).cast('H')`. You could then have your functions accept `wchar[::1]` memoryviews (which should match on Windows I think). Alternatively you could just pass the encoded bytes around and cast the pointers, but that's maybe a little less safe.

Although possibly I'm misunderstanding your problem.

--

---
You received this message because you are subscribed to the Google Groups "cython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cython-users...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/cython-users/740a8b2d-6ceb-43b8-8078-c2ecd9199bfcn%40googlegroups.com.

vinod kc

unread,
1:19 AM (14 hours ago) 1:19 AM
to cython-users
Hi @D Woods,
Thank you for the detailed reply. I will surely try the solution you gave me. But before that, I would like to clarify what I did with ctypes. 
In my class constructor , I did this,
def __init__(self, txt, ....):
    self._title = txt 
    self._wtitle =  ctypes.c_wchar_p(self._title)    
    self._ptr = c3dll.create_new_window(self._wtitle, .....) 

vinod kc

unread,
7:49 AM (8 hours ago) 7:49 AM
to cython-users
@D Woods,
There is a small correction, I don't want the wchar buffer Python object, I just want a wchar ptr to pass to my c3 dll. BTW, I tried this code didn't get much benefit.
cimport cpython.array as carray
ctypedef carray.array PyArray

cdef class CForm:
    cdef str _pyTitle  
    cdef PyArray _titleBuf

    def __cinit__(self, title, width, height, pos, style, autoc = True):
        self._pyTitle = title
        self._titleBuf = carray.array('H', title.encode('utf_16'))
        cdef unsigned short[::1] view = self._titleBuf
        self._ptr = c3dll. create_new_window  (self._pyid, <LPCWSTR>&view[0], width, height, pos, style, autoc)
Reply all
Reply to author
Forward
0 new messages