1

I successfully called a dll library in my Python code. All the By-Value functions worked smoothly. The problem is that my c function require a pointer of doubles array to return the results in. I could not figure out how to define this array.

from ctypes import *


testlib = cdll.LoadLibrary(".\\testdll.dll")


def wrap_func(lib, funcname, restype, argtypes):
    func = lib.__getattr__(funcname)
    func.restype = restype
    func.argtypes = argtypes
    return func


test1 = wrap_func(testlib, 'testfun1', c_double, [c_double, POINTER(c_double), POINTER(c_char)])
test2 = wrap_func(testlib, 'testfun2', c_double, [c_double])

a = 2.5
b = Pointer(c_double)
tstr = Pointer(c_char)
d = test1(a, b, tstr)
print(b.values)

test1 has the problem. test2 worked successfully. The original function test1 n C is:

double testfun1(double x, double* y, char* str)

I expect the output of the function is restored through the array b. The error was:

ctypes.ArgumentError: argument 2: <class 'TypeError'>: expected LP_c_double instance instead of _ctypes.PyCPointerType

Anyone could help me?

2
  • if testfun1 returns an array of doubles in y, how does it know how long the array is? Commented Jul 4, 2019 at 10:57
  • FYI, __getattr__ isn't meant to be called directly. Use func = getattr(lib,funcname) instead. Commented Jul 4, 2019 at 10:57

2 Answers 2

1

In ctypes, POINTER(c_double) is the class representing pointers to c_doubles. What you want to pass is not this class itself, but rather an instance of the class. That's why you got the error message, which means "expected an instance of 'pointer to double' instead of the type 'pointer to double'".

Since these arguments to the C functions do not have sizes associated, I will assume they are in/out parameters, in which case you will need to have them point to real objects. This should work:

b = c_double()
c = c_char()
d = test1(a, byref(b), byref(c))

If they are meant to be arrays, you can create the arrays in Python and then use the POINTER classes you found to create instances:

DoublePointer = POINTER(c_double)
CharPointer = POINTER(c_char)
b = DoublePointer.from_buffer(some_array)
d = test1(a, b, tstr)

If you declare the argument of the C function as c_char_p, you can use Python strings in it directly without having to convert them explicitly to a pointer.

Sign up to request clarification or add additional context in comments.

1 Comment

Sorry. That didn't work. It gave me errors. Anyway I'd like to thank you for your time trying to troubleshoot this error.
0

It sounds like b is an array, but testfun1 does not get an indication of the size of the array and it wasn't mentioned in the question. Here's an example implementation of testfun1 that assumes the array is three elements:

test.c

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

#include <stdio.h>

API double testfun1(double x, double* y, char* str)
{
    printf("%lf %p %s\n",x,y,str);
    y[0] = x;
    y[1] = x * 2;
    y[2] = x * 3;
    return x * 4;
}

Here's the Python code to call it:

test.py

from ctypes import *

dll = CDLL('test')
test1 = dll.testfun1
test1.argtypes = c_double,POINTER(c_double),c_char_p
test1.restype = c_double

a = 2.5
b = (c_double * 3)()  # create an array of three doubles
s = b'test123'
d = test1(a,b,s)
print(d,list(b))

Output

2.500000 000001CA3E31B330 test123
10.0 [2.5, 5.0, 7.5]

2 Comments

Now if I want to pass some numbers inside the array b b = (c_double * 3)() into the test1.c function, what should I do?
@Ziyad pass the numbers as parameters when creating b, or set them with b[0] = ... etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.