Pasando la cadena a Fortran DLL usando ctypes y Python

Estoy tratando de cargar una DLL en Python 2.7 usando ctypes. La DLL se escribió usando Fortran y tiene múltiples subrutinas. Pude configurar con éxito un par de funciones exportadas que los punteros long y double como argumentos.

 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) 

Hasta ahora tan bueno.

El problema surge cuando pruebo otra subrutina llamada Function2 que necesita algunas cadenas como entrada. Las cadenas son todas de longitud fija (255) y también piden la longitud de cada uno de los parámetros de la cadena.

La función se implementa en Fortran de la siguiente manera:

 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) 

La función prototipo en Python se configura de la siguiente manera

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

Y lo llamo usando:

 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) 

Las cuerdas son esencialmente caminos. La función Function2 no reconoce las rutas y prueba un mensaje de error con algunos caracteres no legibles al final, como:

forrtl: severe (43): file name specification error, unit 16, D:\Users\xxxxxxx\Documents\xxxxx\ωa .

Lo que quería que recibiera la función era D:\Users\xxxxxxx\Documents\xxxxx\ . Obviamente, las cadenas no se pasan correctamente.

He leído que Python usa cadenas terminadas en NULL . ¿Puede ser un problema al pasar cadenas a una dll de Fortran? Si es así, ¿cómo me las arreglo?

¿Alguna recomendación?

Related of "Pasando la cadena a Fortran DLL usando ctypes y Python"

Después del comentario de @eryksun, hice los siguientes cambios para que funcione.

Cambió los argtypes a:

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

Y en lugar de pasar la cadena como byref , la cambié a la siguiente.

 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) 

Fue suficiente para pasar los valores directamente.