调用 dll 库
掌握
ctypes模块调用 Windows DLL 的方法理解参数类型映射与返回值处理
能调用系统 DLL 和自定义 DLL
核心讲解
Python 可以通过 ctypes 模块调用 C 语言编写的 DLL 动态库,复用现有 C 代码,调用系统 API,实现 Python 做不到的底层功能。
(1)ctypes 核心作用
加载 DLL 动态库
声明函数的参数类型和返回值类型
实现 Python 类型和 C 类型的转换
调用函数并处理返回值
(2)C 类型与 Python 类型对应
表格
C 类型 | ctypes 类型 | Python 对应 |
|---|---|---|
int | c_int | int |
char* | c_char_p | bytes |
wchar_t* | c_wchar_p | str |
void* | c_void_p | 整数地址 |
float | c_float | float |
double | c_double | float |
(3)加载 DLL 的方式
cdll:cdecl 调用约定,C 标准windll:stdcall 调用约定,Windows API 常用oledll:stdcall,返回 HRESULT
(4)调用步骤
加载 DLL 文件
获取函数对象
声明函数的参数类型(argtypes)和返回值类型(restype)
传入参数调用函数
代码示例
import ctypes
from ctypes import wintypes
# ===== 1. 调用系统DLL:user32.dll =====
# 加载user32.dll(Windows系统库)
user32 = ctypes.windll.user32
# 声明函数:MessageBoxW
# 参数:窗口句柄、文本、标题、按钮类型
user32.MessageBoxW.argtypes = [
wintypes.HWND,
wintypes.LPCWSTR,
wintypes.LPCWSTR,
wintypes.UINT
]
user32.MessageBoxW.restype = ctypes.c_int
# 调用弹出消息框
# 0=确定按钮,48=警告图标
result = user32.MessageBoxW(None, "这是调用DLL弹出的消息", "提示", 0x30 | 0x0)
print("点击了按钮:", result)
# ===== 2. 调用kernel32获取系统信息 =====
kernel32 = ctypes.windll.kernel32
# 获取系统目录
buffer = ctypes.create_unicode_buffer(256)
kernel32.GetSystemDirectoryW(buffer, 256)
print("系统目录:", buffer.value)
# ===== 3. 调用自定义C DLL =====
# 假设你有一个test.dll,里面有add函数 int add(int a, int b)
"""
// C代码
__declspec(dllexport) int add(int a, int b) {
return a + b;
}
"""
# 加载DLL
# test_dll = ctypes.CDLL("test.dll")
# 声明类型
# test_dll.add.argtypes = [ctypes.c_int, ctypes.c_int]
# test_dll.add.restype = ctypes.c_int
# 调用
# result = test_dll.add(10, 20)
# print("add结果:", result)
# ===== 4. 传递字符串参数 =====
# 假设DLL有函数 void print_str(const char* str)
# test_dll.print_str.argtypes = [ctypes.c_char_p]
# test_dll.print_str(b"Hello from Python") # 字节传参
# ===== 5. 结构体示例 =====
class POINT(ctypes.Structure):
_fields_ = [
("x", ctypes.c_long),
("y", ctypes.c_long)
]
# 获取鼠标位置
# user32.GetCursorPos.argtypes = [ctypes.POINTER(POINT)]
# pt = POINT()
# user32.GetCursorPos(ctypes.byref(pt))
# print(f"鼠标位置:x={pt.x}, y={pt.y}")
常见误区
不声明类型:不设置 argtypes 和 restype,默认按 int 处理,很容易崩溃或结果错误
调用约定错:cdecl 和 stdcall 搞混,会报栈错误,Windows API 一般用 windll
字符串编码:C 的 char是字节,Python 要传 bytes;wchar_t才是 Unicode 字符串
32/64 位不匹配:Python 是 64 位就只能调用 64 位 DLL,32 位同理,不兼容
指针参数:传指针要用
byref()或者pointer(),不能直接传变量
课后练习
调用 user32.dll 的 MessageBox 函数,弹出一个提示框
调用 kernel32.dll 获取 Windows 系统版本
尝试调用一个自定义的简单 DLL,实现加法运算
思考:Python 调用 DLL 有什么优势和劣势?
