使用ctypes在Python中调用DLL函数:Python 2.7与3.6兼容问题
解决Python 3.6中ctypes调用C++ DLL函数的问题
你遇到的核心问题是Python 2和Python 3在字符串处理上的本质差异,再结合Windows下LPTSTR类型的字符集依赖,导致了跨版本的调用失败。我来一步步帮你梳理解决:
关键差异拆解
先看你的DLL函数声明:
extern "C" __declspec(dllexport) LONG _stdcall func1(LPTSTR filename, long cbAddress);
这里的LPTSTR是Windows平台的宏,对应TCHAR*:
- 如果DLL是ANSI字符集编译的(老项目默认常用),
TCHAR等价于char,LPTSTR就是char* - 如果是Unicode字符集编译的,
TCHAR等价于wchar_t,LPTSTR就是wchar_t*
Python 2的str本质是字节串,刚好能直接匹配char*参数;但Python 3的str是Unicode字符串,直接传递会和DLL的字符集要求不匹配,导致函数无法正确解析文件路径。
解决方案步骤
1. 确认DLL的实际导出信息
首先要明确你的DLL到底导出的是ANSI还是Unicode版本的函数:
- 打开VS开发者命令行,执行
dumpbin /exports C:\temp\example.dll - 如果看到导出
func1A,说明是ANSI版本;如果是func1W,就是Unicode版本;如果只有func1,则要看编译时的字符集配置
2. 适配Python 3的调用代码
根据字符集选择对应的实现:
情况1:DLL是ANSI字符集(导出func1或func1A)
from ctypes import * # _stdcall调用约定必须用WinDLL加载 mydll = WinDLL(r'C:\temp\example.dll') # 必须显式指定参数和返回值类型,Python3对类型检查更严格 # 如果导出的是func1A,这里改成mydll.func1A mydll.func1.argtypes = [c_char_p, c_long] mydll.func1.restype = c_long # Python3的Unicode字符串转成Windows ANSI编码的字节串(通常是GBK) txt_path = r'C:\temp\your_target_file.txt'.encode('gbk') # 按实际需求传入cbAddress参数 data_handle = mydll.func1(txt_path, 0)
情况2:DLL是Unicode字符集(导出func1W)
from ctypes import * mydll = WinDLL(r'C:\temp\example.dll') # 指定参数为宽字符指针,返回值为long类型 mydll.func1W.argtypes = [c_wchar_p, c_long] mydll.func1W.restype = c_long # Python3的str可以直接作为c_wchar_p传入,ctypes会自动转换为wchar_t* txt_path = r'C:\temp\your_target_file.txt' data_handle = mydll.func1W(txt_path, 0)
为什么Python 2能正常运行?
Python 2中str本身就是字节串,当你用c_char_p包装路径时,刚好匹配ANSI版本DLL的char*参数;而Python 3默认把字符串当成Unicode处理,直接传递会导致DLL收到乱码的路径,自然无法执行解析逻辑。
额外注意事项
- 一定要显式设置
argtypes和restype:这不仅能避免类型不匹配导致的栈错误,还能让ctypes正确处理参数转换 - 如果不确定编码,可通过
sys.getdefaultencoding()查看系统默认编码,Windows下ANSI编码通常为GBK - 如果调用时出现
AccessViolationError,大概率是参数类型不匹配或路径编码错误导致的
内容的提问来源于stack exchange,提问作者FritzS.
相关产品推荐
相关产品推荐

