[英]Passing string to Fortran DLL using ctypes and Python
I am trying to load a DLL in Python 2.7 using ctypes. 我正在尝试使用ctypes在Python 2.7中加载DLL。 The DLL was written using Fortran and has multiple subroutines in it.
DLL是使用Fortran编写的,并且有多个子例程。 I was able to successfully set up couple of the exported functions that that
long
and double
pointers as arguments. 我能够成功设置一些导出的函数,即
long
和double
指针作为参数。
import ctypes as C
import numpy as np
dll = C.windll.LoadLibrary('C:\\Temp\\program.dll')
_cp_from_t = getattr(dll, "CP_FROM_T")
_cp_from_t.restype = C.c_double
_cp_from_t.argtypes = [C.POINTER(C.c_longdouble),
np.ctypeslib.ndpointer(C.c_longdouble)]
# Mixture Rgas function
_mix_r = getattr(dll, "MIX_R")
_mix_r.restype = C.c_double
_mix_r.argtypes = [np.ctypeslib.ndpointer(dtype=C.c_longdouble)]
def cp_from_t(composition, temp):
""" Calculates Cp in BTU/lb/R given a fuel composition and temperature.
:param composition: numpy array containing fuel composition
:param temp: temperature of fuel
:return: Cp
:rtype : float
"""
return _cp_from_t(C.byref(C.c_double(temp)), composition)
def mix_r(composition):
"""Return the gas constant for a given composition.
:rtype : float
:param composition: numpy array containing fuel composition
"""
return _mix_r(composition)
# At this point, I can just pass a numpy array as the composition and I can get the
# calculated values without a problem
comps = np.array([0, 0, 12.0, 23.0, 33.0, 10, 5.0])
temp = 900.0
cp = cp_from_t(comps, temp)
rgas = mix_r(comps)
So far, so good. 到现在为止还挺好。
The problem arises when I try another subroutine called Function2
which needs some strings as input. 当我尝试另一个名为
Function2
子程序需要一些字符串作为输入时,会出现问题。 The strings are all fixed length (255) and they also ask for the length of each of the string parameters. 字符串都是固定长度(255),它们还要求每个字符串参数的长度。
The function is implemented in Fortran as follows: 该函数在Fortran中实现如下:
Subroutine FUNCTION2(localBasePath,localTempPath,InputFileName,Model,DataArray,ErrCode)
!DEC$ ATTRIBUTES STDCALL,REFERENCE, ALIAS:'FUNCTION2',DLLEXPORT :: FUNCTION2
Implicit None
Character *255 localBasePath,localTempPath,InputFileName
Integer *4 Model(20), ErrCode(20)
Real *8 DataArray(900)
The function prototype in Python is set up as follows Python中的函数原型设置如下
function2 = getattr(dll, 'FUNCTION2')
function2.argtypes = [C.POINTER(C.c_char_p), C.c_long,
C.POINTER(C.c_char_p), C.c_long,
C.POINTER(C.c_char_p), C.c_long,
np.ctypeslib.ndpointer(C.c_long , flags='F_CONTIGUOUS'),
np.ctypeslib.ndpointer(C.c_double, flags='F_CONTIGUOUS'),
np.ctypeslib.ndpointer(C.c_long, flags='F_CONTIGUOUS')]
And I call it using: 我用它来称呼它:
base_path = "D:\\Users\\xxxxxxx\\Documents\\xxxxx\\".ljust(255)
temp_path = "D:\\Users\\xxxxxxx\\Documents\\xxxxx\\temp".ljust(255)
inp_file = "inp.txt".ljust(255)
function2(C.byref(C.c_char_p(base_path)),
C.c_long(len(base_path)),
C.byref(C.c_char_p(temp_dir)),
C.c_long(len(temp_dir))),
C.byref(C.c_char_p(inp_file)),
C.c_long(len(inp_file)),
model_array,
data_array,
error_array)
The strings are essentially paths. 字符串本质上是路径。 The function
Function2
does not recognize the paths and proves an error message with some non-readable characters at the end, such as: 函数
Function2
无法识别路径并证明最后带有一些不可读字符的错误消息,例如:
forrtl: severe (43): file name specification error, unit 16, D:\\Users\\xxxxxxx\\Documents\\xxxxx\\ωa
. forrtl: severe (43): file name specification error, unit 16, D:\\Users\\xxxxxxx\\Documents\\xxxxx\\ωa
。
What I wanted the function to receive was D:\\Users\\xxxxxxx\\Documents\\xxxxx\\
. 我想要接收的功能是
D:\\Users\\xxxxxxx\\Documents\\xxxxx\\
。 Obviously, the strings are not passed correctly. 显然,字符串没有正确传递。
I have read that Python uses NULL
terminated strings. 我已经读过Python使用
NULL
终止字符串。 Can that be a problem while passing strings to a Fortran dll? 将字符串传递给Fortran DLL时可能会出现问题吗? If so, how do I get around it?
如果是这样,我该如何解决它?
Any recommendations? 有什么建议?
Following comment from @eryksun, I made the following changes to make it work. 根据@eryksun的评论,我做了以下更改以使其工作。
Changed the argtypes
to: 将
argtypes
更改为:
function2 = getattr(dll, 'FUNCTION2')
function2.argtypes = [C.c_char_p, C.c_long,
C.c_char_p, C.c_long,
C.c_char_p, C.c_long,
np.ctypeslib.ndpointer(C.c_long , flags='F_CONTIGUOUS'),
np.ctypeslib.ndpointer(C.c_double, flags='F_CONTIGUOUS'),
np.ctypeslib.ndpointer(C.c_long, flags='F_CONTIGUOUS')]
And instead of passing the string as byref
, I changed it to the following. 而不是将字符串作为
byref
传递,我将其更改为以下内容。
base_path = "D:\\Users\\xxxxxxx\\Documents\\xxxxx\\".ljust(255)
temp_path = "D:\\Users\\xxxxxxx\\Documents\\xxxxx\\temp".ljust(255)
inp_file = "inp.txt".ljust(255)
function2(base_path, len(base_path), temp_dir, len(temp_dir), inp_file, len(inp_file),
model_array, data_array, error_array)
It was sufficient to pass the values directly. 直接传递值就足够了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.