views:

209

answers:

2

Hi all!

I have a function in a DLL that I have to wrap with python code. The function is expecting a pointer to an array of doubles. This is the error I'm getting:

Traceback (most recent call last):
  File "C:\....\.FROGmoduleTEST.py", line 243, in <module>
    FROGPCGPMonitorDLL.ReturnPulse(ptrpulse, ptrtdl, ptrtdP,ptrfdl,ptrfdP)
ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_c_double instance instead of c_double_Array_0_Array_2

I tried casting it like so:

ptrpulse = cast(ptrpulse, ctypes.LP_c_double)

but I get:

NameError: name 'LP_c_double' is not defined

Any help or direction is greatly appreciated. Thanks all!

A: 

Are you writing the wrapper in Python yourself? The error saying "expected LP_c_double instance" means it's expecting a pointer to a single double, not an array as you've suggested.

>>> ctypes.POINTER(ctypes.c_double * 10)()
<__main__.LP_c_double_Array_10 object at 0xb7eb24f4>
>>> ctypes.POINTER(ctypes.c_double * 20)()
<__main__.LP_c_double_Array_20 object at 0xb7d3a194>
>>> ctypes.POINTER(ctypes.c_double)()
<__main__.LP_c_double object at 0xb7eb24f4>

Either you need to fix your argtypes to correctly expect a pointer to an array of doubles, or you need to pass in a pointer to a single double like the function currently expects.

Mark Rushakoff
A: 

LP_c_double is created dynamically by ctypes when you create a pointer to a double. i.e.

LP_c_double = POINTER(c_double)

At this point, you've created a C type. You can now create instances of these pointers.

my_pointer_one = LP_c_double()

But here's the kicker. Your function isn't expecting a pointer to a double. It's expecting an array of doubles. In C, an array of type X is represented by a pointer (of type X) to the first element in that array.

In other words, to create a pointer to a double suitable for passing to your function, you actually need to allocate an array of doubles of some finite size (the documentation for ReturnPulse should indicate how much to allocate), and then pass that element directly (do not cast, do not de-reference).

i.e.

size = GetSize()
# create the array type
array_of_size_doubles = c_double*size
# allocate several instances of that type
ptrpulse = array_of_size_doubles()
ptrtdl = array_of_size_doubles()
ptrtdP = array_of_size_doubles()
ptrfdl = array_of_size_doubles()
ptrfdP = array_of_size_doubles()
ReturnPulse(ptrpulse, ptrtdl, ptrtdP, ptrfdl, ptrfdP)

Now the five arrays should be populated with the values returned by ReturnPulse.

Jason R. Coombs
I tried this, but I get a writing access violation.If I do:pulse = c_double * 2 * FROGPCGPMonitorDLL.GetSize()ptrpulse = pulse()I get:ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_c_double instance instead of c_double_Array_2_Array_64Arrays in C are contiguous in memory. I just want to point to that memory block, have the C function do its magic, and then look at the result. This is the closest I'm getting - with the error "expected LP_c_double instead of c_double_Array(Dimensions - 2x64, 64x2, or 128 - they should be the same!)"This is interesting...
trayres
ctypes overrides the * operator, so it doesn't function as a typical arithmetic operation. In ctypes, when * is applied to a type, it creates a new type which is an array of the original type with a length of the number specified. I.e. c_int*10 is an array of 10 ints and c_int*10*20 is an array of 20 c_int arrays.
Jason R. Coombs
Hum. I see what you mean! But then...how do I fix this? The C function prototype says the function expects a double pointer, that points at an array of doubles, of size 2*GetSize() [a function that I think is giving me the correct value]. I keep getting a write error, or a type error. This is so strange. I'll email the company right now and see what I can get out of them about it. Thanks for your help so far - it has really been illuminating!
trayres