This worked. Yeah! Thank you so much. Pete
> -----Original Message----- > From: eryksun [mailto:[email protected]] > Sent: Friday, October 17, 2014 8:53 PM > To: Wilson, Pete > Cc: [email protected] > Subject: Re: [Tutor] Registering callbacks and .DLL > > On Thu, Oct 16, 2014 at 6:35 PM, Wilson, Pete <[email protected]> > 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 - [email protected] To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
