3

I am a newbie coder working with ctypes in Python, and attempting to use functions from a DLL written in C. I have found a lot of similar questions to mine on SO but nothing that answers this type of conundrum.

I have loaded the DLL just fine, but one of the functions I need to call asks for a pointer to an array of 6 doubles to dump values into, and I cannot figure out how to give the function what it needs via Python. (My failed attempts to just do this in C are another story.)

I've tried various permutations of ctypes.POINTER(c_double), using byref(), POINTER(c_double * 6), etc and I get type errors at worst, or access violations at best, for all of them.

From the DLL documentation:

int swe_calc_ut (double tjd_ut, int ipl, int iflag, double* xx, char* serr)

The function does calculations using the time in Julian Days to return the longitude, latitude, etc, of a planetary body as doubles.

The closest I've gotten to passing in data types that the DLL will accept is using this code, just trying to get any of the 6 doubles out of swe_calc_ut:

dll = windll.LoadLibrary(# file path)

# retype the args for swe_calc_ut
py_swe_calc_ut = dll.swe_calc_ut
py_swe_calc_ut.argtypes = [c_double, c_int, c_int, c_double, c_char_p]
py_swe_calc_ut.restype = None

tjd = c_double(# some value from elsewhere)

returnarray = c_double()
errorstring = create_string_buffer(126)

py_swe_calc_ut(tjd, c_int(0), c_int(64*1024), returnarray, errorstring)

When I try to run this as-is, I get the error:

OSError: exception: access violation writing 0x0000000000000000

Using byref() gives me a type error, etc.

If anyone could point me in the right direction for getting the desired doubles out of the original DLL function, I would be eternally grateful; I'm stumped and can't get this off the ground.

1 Answer 1

5

This (untested) should work. The 4th parameter is type POINTER(c_double). The equivalent of C's double returnarray[6] type is c_double * 6 and an instance of that type is returnarray= (c_double * 6)(). Also, if you've declared the argument types you don't need to wrap the input parameters such as int(0); passing 0 is fine:

dll = windll.LoadLibrary(# file path)

# retype the args for swe_calc_ut
py_swe_calc_ut = dll.swe_calc_ut
py_swe_calc_ut.argtypes = [c_double, c_int, c_int, POINTER(c_double), c_char_p]
py_swe_calc_ut.restype = None

tdj = 1.5 # some value
returnarray = (c_double * 6)()
errorstring = create_string_buffer(126)

py_swe_calc_ut(tjd, 0, 64*1024, returnarray, errorstring)
Sign up to request clarification or add additional context in comments.

2 Comments

THIS was the answer I was looking for; worked like a charm, and I'm significantly deeper into this code than I imagined myself being able to get today. Thank you!
Answer accepted, thanks for calling my attention to that! Sorry!

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.