Python跨目录运行时调用同目录DLL函数返回0异常问题
问题根因
返回值随运行目录变化的核心原因有两个,都和ctypes加载DLL的默认逻辑有关:
- 你虽然通过脚本绝对路径拼出了
evaluator.dll的完整路径完成加载,但Windows加载DLL的依赖项(包括DLL依赖的其他动态库、内部读取的外部配置/资源文件)时,默认优先搜索Python进程的当前工作目录(即你执行启动命令时所在的目录),不会自动扫描被加载DLL自身的存放目录。从其他目录启动时,DLL找不到同目录下的依赖资源,逻辑走异常分支就会返回0,这类内部加载失败通常不会直接抛出Python层面的报错。 - 代码没有显式声明C函数的参数类型、返回值类型,ctypes默认的类型推导在运行环境变化时可能出现指针解析、内存对齐的偏差,也会导致返回值异常。
修复步骤
按以下逻辑修改代码即可解决跨目录运行异常:
- 调用系统API将DLL所在目录加入系统DLL搜索路径,保证DLL能加载到同目录下的所有依赖
- 显式绑定目标函数的入参类型、返回值类型,消除ctypes隐式类型转换的不确定性
- 若DLL内部硬编码读取相对路径资源,可在调用函数时临时切换工作目录,调用完成后立刻恢复,避免影响其他逻辑
修复后的可直接运行代码:
import ctypes import os dir_path = os.path.dirname(os.path.realpath(__file__)) dll_path = os.path.join(dir_path, "evaluator.dll") # 将DLL所在目录加入系统搜索路径,解决依赖加载问题 ctypes.windll.kernel32.SetDllDirectoryW(dir_path) handle = ctypes.CDLL(dll_path) # 显式声明函数签名,必须配置 handle.My_Function.argtypes = [ctypes.POINTER(ctypes.c_int * 7)] handle.My_Function.restype = ctypes.c_int def get_rank(int_list): IntArray7 = ctypes.c_int * 7 input_array = IntArray7(*int_list) return handle.My_Function(ctypes.byref(input_array))
如果修改后仍存在跨目录返回0的情况,说明DLL内部硬编码读取了当前工作目录下的文件,补充临时切换工作目录的逻辑即可:
def get_rank(int_list): IntArray7 = ctypes.c_int * 7 input_array = IntArray7(*int_list) # 临时切换工作目录到DLL所在目录 old_cwd = os.getcwd() os.chdir(dir_path) res = handle.My_Function(ctypes.byref(input_array)) # 恢复原工作目录 os.chdir(old_cwd) return res
内容的提问来源于stack exchange,提问作者Sievag
相关产品推荐
相关产品推荐

