Accessing contents of an object returned by DLL using ctypes in Python

Question:

The dll returns an object on calling a function using ctypes in python.

It returns the following – say it is named as ReturnO; print(ReturnO) gives the following:

(63484, <DLLname.ClassName object at 0x09D35670>)

The object should return the parameters; their names are: Paramater_1, Parameter_2 and so on. My question is, how do i access the values in Parameter_1, Parameter_2 etc.

if i do a print as follows

print(ClassName.Parameter_1)
print(ClassName.Parameter_2)

i get the following

 Field type=c_float_Array_5, ofs=49483, size=20
 Field type=c_float_Array_5, ofs=49503, size=20

Now, how do I get the value in this array. dotValue (.value) does not work.

Appreciate you help. Thank you.

—————-ADDED/MODIFIED———-BELOW————

below is the code; appreciate your help:

num1=10.1234
int1=10
num11=1.1111
str1=”abcd”

ret=GetOutput_Main(int1,num1,num11,str1)

class ClassName(ctypes.Structure):
  _pack_ = 1
  _fields_ = [("parameter_1", ctypes.c_float * 5),
              ("parameter_2", ctypes.c_float * 5)]

def GetOutput_Main (int2,num2,num22,str2):
    lib = ctypes.WinDLL("mydllname.dll")
    prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ClassName))
    paramflags = (1, "int2",), (1, "num2",), (2, "num22",), (2, "str2",),
    Getoutput_Sub = prototype(("Getoutput", lib), paramflags))
    ret = Getoutput_Sub(int2,num2)
    print(ret) #gives the details of the object
    print(str2.parameter_1) #gives the details of array

the print(ret) gives me:

(63484, <mydllname.ClassName object at 0x09D35670>)

if i do print(str2), I get the following:

<class 'mydllname.ClassName'>

and print(str2.parameter_1) gives me

Field type=c_float_Array_5, ofs=49483, size=20

i am looking for ways to unpack the object, thanks.

if I do, where num22 is the size

UnpackedST = struct.unpack(str2,num22)

i get the following error

Struct() argument 1 must be a str or bytes object, not _ctypes.PyCStructType
Asked By: Confused PK

||

Answers:

If you have a ctypes float array, there are various means to get each of the float.

Example:

We start with a simple python float list, just for the sake of the demo:

>>> python_float_list = [1.5, 2.5, 3.5, 4.5, 5.5]  

Create a ctypes float array from the list:

>>> import ctypes
>>> c_float_array = (ctypes.c_float * 5)(*python_float_list)
>>> c_float_array
<__main__.c_float_Array_5 object at 0x000001D6D9A66A48>

ctypes arrays are subscriptable:

>>> c_float_array[0]
1.5
>>> c_float_array[1]
2.5

You can use a for loop on them too:

>>> for f in c_float_array:
    print(f)


1.5
2.5
3.5
4.5
5.5

As the ctypes arrays are subscriptable, you can get a python list back from them:

>>> list(c_float_array)
[1.5, 2.5, 3.5, 4.5, 5.5]
Answered By: Neitsa

Given your description it looks like you have a C function similar to the following:

test.c

#include <inttypes.h>

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

struct ClassName {
    float parameter_1[5];
    float parameter_2[5];
};

API int __stdcall Getoutput(int a, uint32_t b, uint32_t* pc, struct ClassName* pd) {
    int i;
    *pc = a + b;
    for(i = 0; i < 5; ++i) {
        pd->parameter_1[i] = i * .5f;
        pd->parameter_2[i] = i * .25f;
    }
    return a * b;
}

Your paramflags argument indicates two inputs (type 1) and two return values (type 2). Simply pass the two required input values, and store the result in a tuple. You can call list() on or slice the arrays to access their elements. I provided a __repr__ function so the class can display itself when printed.

test.py

import ctypes as ct

class ClassName(ct.Structure):

    _fields_ = (('parameter_1', ct.c_float * 5),
                ('parameter_2', ct.c_float * 5))

    def __repr__(self):
        '''Return string describing how to print ClassName object.
        '''
        # Note that slicing an array produces a list of its elements.
        return f'ClassName({self.parameter_1[:]}, {self.parameter_2[:]})'

lib = ct.WinDLL('./test')
prototype = ct.WINFUNCTYPE(ct.c_int, ct.c_int, ct.c_uint32, ct.POINTER(ct.c_uint32), ct.POINTER(ClassName))
paramflags = (1, 'int2'), (1, 'num2'), (2, 'num22'), (2, 'str2')
Getoutput = prototype(('Getoutput', lib), paramflags)

pc, pd = Getoutput(10, 11)
print(f'{pc=} {pd=}')

Output:

pc=21 pd=ClassName([0.0, 0.5, 1.0, 1.5, 2.0], [0.0, 0.25, 0.5, 0.75, 1.0])
Answered By: Mark Tolonen
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.