2014-05-13 14 views
5

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ỏ longdouble 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?

+0

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

+0

@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

Trả lời

3

Nhận xét sau từ @eryksun, tôi đã thực hiện các thay đổi sau để làm cho nó hoạt động.

Thay đổi argtypes tới:

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

Và thay vì đi qua các chuỗi như byref, tôi đã thay đổi nó như sau.

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) 

Đủ để chuyển trực tiếp giá trị.

+1

Theo tài liệu của Intel về [Lập trình ngôn ngữ hỗn hợp] (https://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/2011Update/fortran/lin/bldaps_for/common/bldaps_bk_hndl_dtypes.htm) , độ dài được nối vào cuối danh sách đối số, không xen kẽ. Ngoài ra, đối số là 'c_int32' trong quy trình 32 bit và' c_int64' trong quy trình 64 bit.'c_long' luôn là' c_int32' trong Windows, nhưng trong thực tế bạn sẽ không gặp vấn đề gì trừ khi bạn cần một chuỗi dài hơn '2 ** 31 - 1'. – eryksun

Các vấn đề liên quan