I'm trying to make Python use a Fortran DLL (call by referance). When running Fortran 90 code, it works fine, but will not work in Python; it only gives "access violation" errors or "called with not enough arguments".
The python code:
from ctypes import *
mydll = cdll.LoadLibrary("test.dll")
# This function works.
print mydll.XIT() # prints 0
mydll.GetInfo.argtypes = [POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_char_p)]
rm = c_int()
rf = c_int()
vm = (c_int * 5)()
vf = (c_int * 5)()
np = c_int(14)
p = (c_int * 14)()
filename = "test"
fn = c_char_p(filename)
nc = c_int(len(filename)) # length of string. (Hidden argument in Fortran)
# throws insufucient arguments
print mydll.GetInfo(rm,rf,vm,vf,np,p,fn,nc)
# throws access violation
print mydll.GetInfo(byref(rm),byref(rf),byref(vm),byref(vf),byref(np),byref(p),byref(fn),byref(nc))
The fortran90 code:
program test
implicit none
integer, parameter :: np = 14
integer :: rm, rf
integer, dimension(5) :: vm, vf
integer, dimension(np) :: p
character(len=80) :: fn
interface
integer function GetInfo(rm, rf, vm, vf, np, p, fn)
!dec$ attributes dllimport, stdcall, reference, decorate, alias:'GetInfo' :: GetInfo
implicit none
character(len=*), intent(in) :: fn
integer, intent(in) :: np
integer, intent(out) :: rm,rf
integer, intent(out), dimension(5) :: vm,vf
integer, intent(out), dimension(np) :: p
end function GetInfo
end interface
fn = "test"
print *, GetInfo(rm, rf, vm, vf, np, p, fn)
end program test
Edit: I've modified my code to now not pass the string length as reference. I've switched the cdll to windll, and removed the double POINTER and byref() usage. Also, c_char_p is already a pointer, so it doesn't need a POINTER.
I'm not sure on what the conventions of your Fortran compiler are so I'll answer with some general points rather than specifics:
windll rather than cdll.POINTER(c_char_p) is right? That is a pointer to a pointer to null-terminated string. I think you probably have an extra layer of indirection at the Python end, but I'm not 100% sure of that.Otherwise I can't see anything wrong, although I know nothing whatsoever about Fortran so I can't vouch for that.
If I were you I would cut this right back to a trivial function that passes a single int parameter. Then I would add an int array and check that you can transfer data both ways for such a parameter. Then move up to a string. Don't attempt such a complicated parameter list from scratch because you just give yourself too many potential pitfalls and it's hard to know where to look first.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With