Tôi đang cố gắng tải một DLL trong Python 2.7 bằng cách sử dụng ctypes. DLL được viết bằng Fortran và có nhiều chương trình con trong đó. Tôi đã có thể thiết lập thành công một vài hàm được xuất mà các con trỏ long
và double
làm đối số.Truyền chuỗi tới Fortran DLL bằng cách sử dụng ctypes và Python
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)
Cho đến giờ, rất tốt.
Sự cố phát sinh khi tôi thử một chương trình con khác được gọi là được gọi là Function2
cần một số chuỗi làm đầu vào. Các chuỗi là tất cả độ dài cố định (255) và chúng cũng yêu cầu độ dài của mỗi tham số chuỗi.
Chức năng được thực hiện trong Fortran như sau:
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)
Nguyên mẫu hàm trong Python được thiết lập như sau
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')]
Và tôi gọi nó là sử dụng:
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)
Các chuỗi cơ bản là đường dẫn. Hàm Function2
không nhận ra đường dẫn và chứng minh thông báo lỗi với một số ký tự không thể đọc được ở cuối, chẳng hạn như:
forrtl: severe (43): file name specification error, unit 16, D:\Users\xxxxxxx\Documents\xxxxx\ωa
.
Điều tôi muốn chức năng nhận là D:\Users\xxxxxxx\Documents\xxxxx\
. Rõ ràng, các chuỗi không được truyền chính xác.
Tôi đã đọc rằng Python sử dụng NULL
chuỗi bị chấm dứt. Có thể đó là một vấn đề trong khi đi dây đến một dll Fortran? Nếu vậy, làm thế nào để tôi có được xung quanh nó?
Bất kỳ đề xuất nào?
OK. Sẽ thay đổi 'argtypes' để truyền theo giá trị. Đối với nhận xét trước, bạn đã đúng. Nó phải là chức năng nguyên mẫu. Đã thực hiện các thay đổi ở trên. Đã phải đơn giản hóa một số mã như ban đầu nó được triển khai như một lớp. – d0m1n0
@eryksun Điều đó đã giúp ích. Bây giờ các chuỗi đang được thông qua correclty. Dll vẫn có vẻ gặp rắc rối với 'Function2'. Sẽ phải làm việc với các tác giả của nó cho điều đó. – d0m1n0