2017-01-31 2 views
3

Ich schreibe Framework in Python 2.7, die Funktionalität zum Testen von C geschrieben APIs bieten würde. Ich habe die DLL und den C-Quellcode selbst. Das Problem ist, dass einige der C-API-Funktionen als Eingabe-Struktur eines Callback-Funktionen benötigen und Ich kann nicht finden, wie Sie in Python Struktur erstellen, welche Felder sind die C-Funktionszeiger. Ich weiß, wie man Callback-Funktion in Python mit ctypes erstellen, aber ich muss diese Callbacks in C-Struktur packen, um an C API übergeben. All dies in Code wie folgt aussieht:C-Funktion Pointer-Struktur in Python erstellen

Die C Funktionszeiger und die C-Struktur:

#define DRIVERCALLAPI 
typedef void*(DRIVERCALLAPI *fn_DRV_COMM_Open)(void*); 
typedef void(DRIVERCALLAPI *fn_DRV_COMM_Close)(void*); 
typedef int(DRIVERCALLAPI *fn_DRV_COMM_Transfer)(void *, unsigned char *, int); 

typedef struct DriverCallbacks_t 
{ 
    fn_DRV_COMM_Open    drvcomm_Open; 
    fn_DRV_COMM_Close    drvcomm_Close; 
    fn_DRV_COMM_Transfer   drvcomm_Transfer; 
} DriverCallbacks; 

typedef struct InitDataEntry_t 
{ 
    char iface[64]; 
    void* handle; 
} InitDataEntry; 

Wo Griff auf ein Objekt von DriverCallbacks.

typedef struct InitDataContainer_t 
{ 
    uint32_t size; 
    uint32_t id; 
    InitDataEntry* data; 
} InitDataContainer; 

Der Zeiger eines InitDataContainer sollte auf die API-Funktion übergeben werden.

void* dev_Create(void* args) 

Die API initialisiert die Callback-Funktionen mit entsprechenden Funktionen, um sie später zu verwenden. Ich muss irgendwie Python-Strukturen von DriverCallbacksInitDataEntry und InitDataContainer erstellen. Irgendein Hinweis darauf, wie es erreicht werden kann? Danke im Voraus !

Antwort

2

Nach vielen Experimenten fand ich schließlich, wie man Python-Strukturen erzeugt, die C-Strukturen mit Funktionszeigern als Felder entsprechen. Die Idee ist Leere Zeiger stattdessen das heißt c_void_p von ctypes zu verwenden. Für die vorgesehenen Beispiel wäre der Python-Code sein:

from ctypes import * 
class DriverCallbacks(Structure): 
    _fields_ = [ 
     ("drvcomm_Open",  c_void_p), 
     ("drvcomm_Close", c_void_p), 
     ("drvcomm_Transfer", c_void_p) 
    ] 

class InitDataEntry(Structure): 
    _fields_ = [ 
     ("iface", 64 * c_byte), 
     ("handle", c_void_p) 
    ] 

class InitDataContainer(Structure): 
    _fields_ = [ 
     ("size", c_uint), 
     ("id",  c_uint), 
     ("data", POINTER(InitDataEntry)) 
    ] 

Die Erstellung der Objekte und der Bibliothek Funktionsaufruf so sein könnte (es ist getestet und funktioniert für mich):

lib = cdll.LoadLibrary(LIBNAME) 

driverFuncList = DriverCallbacks() 
driverFuncList.drvcomm_Open = cast(lib.ftdi_open, c_void_p) 
driverFuncList.drvcomm_Close = cast(lib.ftdi_close, c_void_p) 
driverFuncList.drvcomm_Transfer = cast(lib.ftdi_transfer, c_void_p) 

initData = InitDataEntry() 
libc = cdll.msvcrt 
libc.strcpy(byref(initData.iface), c_char_p("DriverCallbacks")) 
initData.handle = cast(pointer(driverFuncList), c_void_p) 

initDataCont = InitDataContainer() 
initDataCont.size = c_uint(3) 
initDataCont.id = c_uint(0) 
initDataCont.data = pointer(initData) 

ret = lib.dev_Create(byref(initDataCont)) 

Die driverFuncList Objekt kann auch aus der C-Bibliothek gefüllt werden, wenn es eine solche Funktion gibt, die die Callback-Funktionszeiger setzt.