使用Ctypes Python访问冲突<> Fortran DLL

时间:2011-11-24 14:47:59

标签: python dll fortran ctypes

我正在尝试让Python使用Fortran DLL(通过referance调用)。运行Fortran 90代码时,它运行正常,但不能在Python中运行;它只会出现“访问冲突”错误或“没有足够的参数调用”。

python代码:

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))

fortran90代码:

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

编辑: 我已修改我的代码,现在不传递字符串长度作为参考。我已将cdll切换为windll,并删除了双POINTER和byref()用法。此外,c_char_p已经是指针,因此它不需要POINTER。

1 个答案:

答案 0 :(得分:4)

我不确定您的Fortran编译器的约定是什么,所以我将回答一些一般性的观点,而不是细节:

  1. 您的通话约定不匹配。 Fortran代码指定stdcall,ctypes代码指定cdecl。你需要让它们匹配。例如,将ctypes更改为使用windll而不是cdll
  2. 您确定POINTER(c_char_p)是对的吗?这是一个指向以null结尾的字符串的指针。我想你可能在Python端有一个额外的间接层,但我不是百分之百确定。
  3. @eryksun在评论中声明隐式字符串长度参数是按值而不是按引用传递的。
  4. 否则我看不出任何错误,虽然我对Fortran一无所知,所以我不能保证这一点。

    如果我是你,我会将其切换回一个传递单个int参数的简单函数。然后我会添加一个int数组并检查您是否可以通过这两种方式传输数据。然后向上移动到一个字符串。不要从头开始尝试这么复杂的参数列表,因为你只是给自己太多潜在的陷阱而且很难知道首先要看哪里。