使用Python调用EPlusWth.dll时遭遇ctypes参数错误
解决EPlusWth.dll气象文件转换的ctypes调用错误
问题场景
使用Python 3.10 32位调用EnergyPlus的EPlusWth.dll,将自定义格式的气象文件批量转换为EPW格式时,出现两类错误:
- 带
byref()调用时:ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type - 移除
byref()后:OSError: exception: access violation writing 0x00000000
原问题代码
import ctypes from ctypes import byref, c_bool, c_char_p, c_long conversionDLL = ctypes.WinDLL('C:/[...]/EPlusWth.dll') conversionPrototype = ctypes.WINFUNCTYPE( c_bool, # Output type. c_char_p, c_long, # Input file type and string length. c_char_p, c_long, # Output file type and string length. c_char_p, c_long, # Input file name and string length. c_char_p, c_long, # Output file name and string length. c_bool, # Output variable ErrorFlag to use. Positive, if an error occurred. ) conversionApiParams = ( (1, 'strInType ', 'CUSTOM'), (1, 'InTypeLen', 0), (1, 'strOutType', 'EPW'), (1, 'OutTypeLen', 3), (1, 'strInFileName', ''), (1, 'InFileNameLen', 0), (1, 'strOutFileName', ''), (1, 'OutFileNameLen', 0), (1, 'ErrorFlag ', False), ) conversionApi = conversionPrototype(('ProcessWeather', conversionDLL), conversionApiParams) inputFileType = b'CUSTOM' outputFileType = b'EPW' inputFileName = b'C:/[...]/BAS_2035_RCP85_DRY.csv' outputFileName = b'C:/[...]/BAS_2035_RCP85_DRY.epw' errorFlag = c_bool(False) strInType = c_char_p(inputFileType) strOutType = c_char_p(outputFileType) strInFileName = c_char_p(inputFileName) strOutFileName = c_char_p(outputFileName) InTypeLen = c_long(len(inputFileType)) OutTypeLen = c_long(len(outputFileType)) InFileNameLen = c_long(len(inputFileName)) OutFileNameLen = c_long(len(outputFileName)) conversionApi( byref(strInType), byref(InTypeLen), byref(strOutType), byref(OutTypeLen), byref(strInFileName), byref(InFileNameLen), byref(strOutFileName), byref(OutFileNameLen), errorFlag, )
错误原因
- 参数传递类型不匹配:对输入字符串参数使用
byref(),导致传递了指针的指针,与函数期望的char*类型冲突。 - 输出参数处理错误:
ErrorFlag是输出参数(函数需要修改其值),原代码直接传递值而非指针,引发内存访问违规。 - 默认参数干扰:通过
conversionApiParams设置默认参数容易导致参数传递冲突,降低代码可靠性。
修正后的代码
import ctypes from ctypes import byref, c_bool, c_char_p, c_long, WINFUNCTYPE, POINTER # 加载32位EPlusWth.dll,替换为实际路径 eplus_wth_dll = ctypes.WinDLL('C:/path/to/preprocess/EPlusWth.dll') # 定义ProcessWeather函数原型:返回值为布尔型,参数含输出用的错误标志指针 ProcessWeather = WINFUNCTYPE( c_bool, c_char_p, c_long, # 输入文件类型、类型长度 c_char_p, c_long, # 输出文件类型、类型长度 c_char_p, c_long, # 输入文件路径、路径长度 c_char_p, c_long, # 输出文件路径、路径长度 POINTER(c_bool) # 错误标志(输出参数,需传指针) )(('ProcessWeather', eplus_wth_dll)) # 显式声明参数类型,提升调用安全性 ProcessWeather.argtypes = [ c_char_p, c_long, c_char_p, c_long, c_char_p, c_long, c_char_p, c_long, POINTER(c_bool) ] ProcessWeather.restype = c_bool # 准备参数:所有字符串用字节串,符合C语言字符串要求 input_type = b'CUSTOM' output_type = b'EPW' input_file = b'C:/[...]/BAS_2035_RCP85_DRY.csv' output_file = b'C:/[...]/BAS_2035_RCP85_DRY.epw' error_flag = c_bool(False) # 调用函数:输入参数直接传递,错误标志传指针 conversion_success = ProcessWeather( input_type, len(input_type), output_type, len(output_type), input_file, len(input_file), output_file, len(output_file), byref(error_flag) ) # 输出结果 if conversion_success: print("气象文件转换完成,EPW已生成") else: print(f"转换失败,错误状态:{error_flag.value}")
关键调整说明
- 移除不必要的
byref():输入字符串参数直接传递字节串(ctypes会自动转换为char*),匹配函数期望的类型。 - 修正输出参数传递:
ErrorFlag改为传递指针(byref(error_flag)),确保函数能修改其值。 - 简化函数定义:放弃默认参数设置,直接显式声明函数原型和参数类型,避免参数冲突。
- 调用约定确认:使用
WinDLL对应stdcall调用约定,符合EnergyPlus DLL的编译规范。
额外注意事项
- 必须保证Python版本(32位)与
EPlusWth.dll的位数一致。 - 输入文件路径需确保DLL有权限访问,避免路径中包含特殊字符。
- 若需调用
SetFixOutOfRangeData,需按同样规则定义函数原型:# 示例:定义SetFixOutOfRangeData函数 SetFixOutOfRangeData = WINFUNCTYPE( None, c_char_p, c_long )(('SetFixOutOfRangeData', eplus_wth_dll)) # 调用:设置修复超出范围的数据 SetFixOutOfRangeData(b'yes', len(b'yes'))
内容的提问来源于stack exchange,提问作者Degux
相关产品推荐
相关产品推荐

