Search code examples
pythonpointersdllpass-by-referencectypes

What should I do to have multiple ctypes data types assigned to a single ctypes instance in Python?


I'm converting a C code into a Python code that uses a .dll file. The syntax for accessing the commands from the DLL is given below:

cnc_rdmacro(unsigned short FlibHndl, short number, short length, ODBM *macro);

C code Pointer to the odbm data structure is as follows:

typedef struct  odbm {
    short   datano ;    /* custom macro variable number */
    short   dummy ;     /* (not used) */
    long    mcr_val ;   /* value of custom macro variable */
    short   dec_val ;   /* number of places of decimals */
} ODBM ;

C code used to access the dll command:

  short example( short number )
{
        ODBM macro ;
        char strbuf[12] ;
        short ret ;
        ret = cnc_rdmacro( h, number, 10, &macro ) ;

The python code that I converted according to the above C code is as follows:

import ctypes
fs = ctypes.cdll.LoadLibrary(r".dll filepath")
ODBM = (ctypes.c_short * 4)() #the datatype conversion code from the above C code
ret = fs.cnc_rdmacro(libh, macro_no, 10, ctypes.byref(ODBM))

I can get the output without any errors in the above code.

The actual data structure of the ODBM has declared 4 variables of datatypes short, short, long and short which are implemented in the C code. But I had declared the ODBM data structure in python as ctypes.c_short * 4 i.e, 4 variables of short data types.

But my necessity is to declare the ODBM structure the same as in the C code and pass it to the ctypes.byref().

The ultimate solution is to include multiple data types in a single variable as a ctypes instance. Kindly help me out.


Solution

  • A ctypes.Structure should be used here:

    import ctypes
    
    class ODBM(ctypes.Structure):
        _fields_ = [("datano", ctypes.c_short),
                    ("dummy", ctypes.c_short),
                    ("mcr_val", ctypes.c_long),
                    ("dec_val", ctypes.c_short)]
    
    fs = ctypes.cdll.LoadLibrary(r".dll filepath")
    odbm = ODBM()
    ret = fs.cnc_rdmacro(libh, macro_no, 10, ctypes.byref(odbm))
    
    print(odbm.mcr_val)