On Thu, Oct 16, 2014 at 6:35 PM, Wilson, Pete <pete.wil...@atmel.com> wrote: > > The .DLL was written in C++ is working with C++ apps calling it.
ctypes doesn't support the platform C++ ABI (I don't think the VC++ ABI is even stable), classes, STL containers, or exceptions [*]. It isn't "cpptypes". To work with ctypes, a C++ library needs an extern "C" interface. The library you're using probably qualifies, but try a simple test program in C before jumping into ctypes. [*] On Windows ctypes has limited support for Structured Exception Handling (SEH), a Microsoft extension of ANSI C. Inadvertently it also handles any exception raised by Win32 RaiseException, such as VC++ exceptions. The code for VC++ exceptions is 0xE06D7363, i.e. "\xE0" "msc". ctypes isn't looking for this code and doesn't delve deeper to get the C++ exception type, so the OSError it raises is almost useless. Pretend this doesn't exist. SEH support is only implemented for the few cases ctypes handles explicitly such as access violations. > I tried the methods in section 15.17.1.17 with the qsort() and CFUNCTYPE, > but it is not working. My code and the .dll are attached. > > from ctypes import * > > pt_dll = cdll.LoadLibrary("c:/py_stuff/ProductionTest.dll") You can use CDLL instead. It's fewer keystrokes. from ctypes import * pt_dll = CDLL("c:/py_stuff/ProductionTest.dll") If the functions use the stdcall convention, substitute WinDLL for CDLL. If there's a mix of calling conventions you can simply load the library twice, once as CDLL and again as WinDLL. They'll each have the same _handle attribute. You can also define prototypes manually via CFUNCTYPE and WINFUNCTYPE. Then instantiate them with a 2-tuple (name_or_ordinal, library), e.g. libc = CDLL('msvcr100') atoi_t = CFUNCTYPE(c_int, c_char_p) atoi = atoi_t(('atoi', libc)) >>> atoi(b'42') 42 FYI, 64-bit Windows has a single calling convention, so if you switch to 64-bit Python you don't have to worry about cdecl vs stdcall. http://en.wikipedia.org/wiki/X86_calling_conventions > reg_send_serial_data = pt_dll.RegSendSerialData > > class SendSerialData_t(Structure): > _fields_ = [("tx_data", c_void_p), > ("size", c_uint8)] > > send_serial_data = SendSerialData_t() SendSerialData_t is a function pointer type, not a data structure. Here are the C prototypes from the attached PDF: typedef void (*SendSerialData_t) (uint8_t *tx_data, uint8_t size); void RegSendSerialData(SendSerialData_t SendSerialData); A SenedSerialData_t function takes two parameters (uint8_t *, uint8_t) and returns nothing (void). ctypes declarations: SendSerialData_t = CFUNCTYPE(None, POINTER(c_uint8), c_uint8) reg_send_serial_data = pt_dll.RegSendSerialData reg_send_serial_data.argtypes = [SendSerialData_t] reg_send_serial_data.restype = None The first argument to CFUNCTYPE is the return type. Use None for void. Next define the Python callback. def send_serial_data(tx_data, size): # testing print tx_data, size print tx_data[:size] cb_send_serial_data = SendSerialData_t(send_serial_data) Finally, register the callback with the library: reg_send_serial_data(cb_send_serial_data) It's vital that you keep a reference to cb_send_serial_data (as a global, an instance attribute, in a container, etc). This prevents the callback from being deallocated while it's possible the library can call it. Otherwise at best you'll get an access violation (or segfault on POSIX systems), but probably a less obvious error. Next your test code sets up ProdBatVolRequest, which is prototyped as follows: typedef void (*BatVolReadRequest_cb)(uint16_t bat_vol, uint8_t status); typedef struct { BatVolReadRequest_cb BatVolReadConf; } BatVolReadRequest_t; void ProdBatVolReadRequest(BatVolReadRequest_t BatVolReadParam); ProdBatVolReadRequest is passed a struct by value that consists of a single function pointer. You can skip defining this struct and just pass the function pointer. It's the same ABI for x86 and x64. BatVolReadRequest_t = CFUNCTYPE(None, c_uint16, c_uint8) prod_bat_vol_read_request = pt_dll.ProdBatVolReadRequest prod_bat_vol_read_request.argtypes = [BatVolReadRequest_t] prod_bat_vol_read_request.restype = None def bat_vol_read(bat_vol, status): # testing print bat_vol, status cb_bat_vol_read = BatVolReadRequest_t(bat_vol_read) prod_bat_vol_read_request(cb_bat_vol_read) Remember to keep a reference to cb_bat_vol_read. HTH _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor