简体   繁体   English

使用ctypes和Python将字符串传递给Fortran DLL

[英]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. 我能够成功设置一些导出的函数,即longdouble指针作为参数。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM