对于编程语言来说,是如何实现扩展的,例如 lua语言,python语言,在 windows系统下,又是如何跟下层驱动进行交互的,也就是说如何调用下层驱动程序。
下面就这些问题做一些探究。
先解释语言扩展的通用概念,然后分别说明Lua和Python的扩展实现方式,接着重点剖析Windows驱动交互的完整调用链条,最后用代码示例帮助用户理解。如果搜索结果充分,可以用一个清晰的层次图展示从脚本到驱动的调用流程。
考虑到需要深入解析,准备用一个调用层次图直观展示从Python到驱动的完整流程,放在回答前半部分帮助用户建立整体认知。然后分别说明Lua的C API/FFI机制和Python的扩展模块/pywin32方式,最后用调用DeviceIoControl的具体代码示例收尾。
要让 Python 或 Lua 这样的高级语言在 Windows 下操作硬件(如控制风扇转速、读取 USB 设备),它们必须通过操作系统这座“桥”。这种能力并非与生俱来,而是通过一套精心设计的“扩展机制”实现的。
简单来说,这个过程分为两步:语言如何扩展(高级语言调用底层代码)和系统如何交互(底层代码与驱动对话)。
下面这张图清晰地展示了从你的 Python/Lua 代码到硬件驱动的完整调用链条:
#mermaid-svg-jmadjV6wLPTSBeLG{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jmadjV6wLPTSBeLG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jmadjV6wLPTSBeLG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jmadjV6wLPTSBeLG .error-icon{fill:#552222;}#mermaid-svg-jmadjV6wLPTSBeLG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jmadjV6wLPTSBeLG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jmadjV6wLPTSBeLG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jmadjV6wLPTSBeLG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jmadjV6wLPTSBeLG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jmadjV6wLPTSBeLG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jmadjV6wLPTSBeLG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jmadjV6wLPTSBeLG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jmadjV6wLPTSBeLG .marker.cross{stroke:#333333;}#mermaid-svg-jmadjV6wLPTSBeLG svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jmadjV6wLPTSBeLG p{margin:0;}#mermaid-svg-jmadjV6wLPTSBeLG .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-jmadjV6wLPTSBeLG .cluster-label text{fill:#333;}#mermaid-svg-jmadjV6wLPTSBeLG .cluster-label span{color:#333;}#mermaid-svg-jmadjV6wLPTSBeLG .cluster-label span p{background-color:transparent;}#mermaid-svg-jmadjV6wLPTSBeLG .label text,#mermaid-svg-jmadjV6wLPTSBeLG span{fill:#333;color:#333;}#mermaid-svg-jmadjV6wLPTSBeLG .node rect,#mermaid-svg-jmadjV6wLPTSBeLG .node circle,#mermaid-svg-jmadjV6wLPTSBeLG .node ellipse,#mermaid-svg-jmadjV6wLPTSBeLG .node polygon,#mermaid-svg-jmadjV6wLPTSBeLG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jmadjV6wLPTSBeLG .rough-node .label text,#mermaid-svg-jmadjV6wLPTSBeLG .node .label text,#mermaid-svg-jmadjV6wLPTSBeLG .image-shape .label,#mermaid-svg-jmadjV6wLPTSBeLG .icon-shape .label{text-anchor:middle;}#mermaid-svg-jmadjV6wLPTSBeLG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jmadjV6wLPTSBeLG .rough-node .label,#mermaid-svg-jmadjV6wLPTSBeLG .node .label,#mermaid-svg-jmadjV6wLPTSBeLG .image-shape .label,#mermaid-svg-jmadjV6wLPTSBeLG .icon-shape .label{text-align:center;}#mermaid-svg-jmadjV6wLPTSBeLG .node.clickable{cursor:pointer;}#mermaid-svg-jmadjV6wLPTSBeLG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jmadjV6wLPTSBeLG .arrowheadPath{fill:#333333;}#mermaid-svg-jmadjV6wLPTSBeLG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jmadjV6wLPTSBeLG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jmadjV6wLPTSBeLG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jmadjV6wLPTSBeLG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jmadjV6wLPTSBeLG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jmadjV6wLPTSBeLG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jmadjV6wLPTSBeLG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jmadjV6wLPTSBeLG .cluster text{fill:#333;}#mermaid-svg-jmadjV6wLPTSBeLG .cluster span{color:#333;}#mermaid-svg-jmadjV6wLPTSBeLG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jmadjV6wLPTSBeLG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jmadjV6wLPTSBeLG rect.text{fill:none;stroke-width:0;}#mermaid-svg-jmadjV6wLPTSBeLG .icon-shape,#mermaid-svg-jmadjV6wLPTSBeLG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jmadjV6wLPTSBeLG .icon-shape p,#mermaid-svg-jmadjV6wLPTSBeLG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jmadjV6wLPTSBeLG .icon-shape rect,#mermaid-svg-jmadjV6wLPTSBeLG .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jmadjV6wLPTSBeLG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jmadjV6wLPTSBeLG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jmadjV6wLPTSBeLG :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
调用Windows系统API
发起IRP请求
路由请求
直接操作
返回数据/状态
返回结果给
Python / Lua 脚本代码
语言的扩展机制(如 Python C-API, Lua FFI)
Windows API 层(如 kernel32.dll 中的 DeviceIoControl)
Windows 执行体/内核
设备驱动程序(运行在权限最高的 Ring 0)
硬件设备
接下来,我们结合这张图,从“语言扩展”和“系统交互”两个层面详细拆解。
🔌 语言的扩展能力:架起第一座桥
高级语言本身并不包含操作硬件的指令,但它们都提供了“外延”的机制,让你能调用用C语言编写的代码。因为C语言可以与操作系统进行最直接的对话。
-
Lua的扩展方式:Lua以其极佳的“可嵌入性”和“可扩展性”闻名。它主要通过 C API 和 FFI(外部函数接口) 实现扩展。
- C API:这是最基础的方式。你可以用C语言编写一个动态链接库(DLL),在里面实现具体的功能,然后Lua通过C API调用这个DLL里的函数。
- FFI:这是一种更先进、更便捷的方式。通过ffi库,你可以在Lua代码中直接声明并调用C函数,访问C数据结构,而无需为每个函数单独编写C封装代码。这极大地简化了调用过程。
-
Python的扩展方式:Python的扩展机制同样强大,主要途径如下:
- C扩展:这是最正统的方式。你需要按照Python官方提供的C API规范编写代码,然后将其编译成Windows下的.pyd文件(本质就是DLL)。Python在导入这个模块时,就可以直接调用其中的C函数了。
- ctypes库:这是Python内置的、调用C库的利器。你无需编写任何C代码,直接在Python中用ctypes加载一个已有的DLL,并声明函数的参数和返回类型,就可以像调用普通Python函数一样调用DLL里的函数了。
- pywin32库:这是一个针对Windows API的“超级工具箱”。它本身就是一个巨大的Python C扩展,封装了数以万计的Windows API函数和COM组件。通过它,你可以在Python中轻松操作注册表、服务、进程等系统级资源。
🚀 深入底层:如何与驱动交互?
当你的C语言代码(无论是Lua的C模块,还是Python的pywin32)获得了执行权限后,它需要调用Windows提供的特定API来与驱动通信。DeviceIoControl是其中最核心、最通用的函数。
下面以Python为例,模拟一个读取USB设备序列号的完整流程:
import ctypes
from ctypes import wintypes
# 1. 加载Windows的核心API库
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
# 2. 定义必要的常量和数据结构
GENERIC_READ = 0x80000000
OPEN_EXISTING = 3
FILE_FLAG_OVERLAPPED = 0x40000000
INVALID_HANDLE_VALUE = –1
# 假设这是该USB设备驱动定义的、用于获取序列号的控制码
# 实际值由驱动开发者定义,通常在设备头文件中
IOCTL_GET_SERIAL_NUMBER = 0x80002000 # 举例,非真实值
# 3. 调用Windows API打开设备
# 设备路径,例如第一个USB设备
device_path = r"\\\\.\\USB#VID_1234&PID_5678#1234567890#{some-guid}"
hDevice = kernel32.CreateFileW(
device_path, # 设备路径
GENERIC_READ, # 访问权限
0, # 共享模式
None, # 安全属性
OPEN_EXISTING, # 创建方式
FILE_FLAG_OVERLAPPED, # 标志和属性
None # 模板文件句柄
)
if hDevice == INVALID_HANDLE_VALUE:
print(f"打开设备失败,错误码: {ctypes.get_last_error()}")
else:
# 4. 准备输入输出缓冲区
in_buffer = None # 此操作无需输入数据
in_buffer_size = 0
out_buffer = ctypes.create_string_buffer(256) # 准备接收256字节数据
out_buffer_size = ctypes.sizeof(out_buffer)
bytes_returned = wintypes.DWORD(0)
# 5. 调用核心函数 DeviceIoControl,与驱动通信
result = kernel32.DeviceIoControl(
hDevice, # 设备句柄
IOCTL_GET_SERIAL_NUMBER, # 控制码,告诉驱动要做什么
in_buffer, # 输入缓冲区指针
in_buffer_size, # 输入缓冲区大小
ctypes.byref(out_buffer), # 输出缓冲区指针
out_buffer_size, # 输出缓冲区大小
ctypes.byref(bytes_returned), # 实际返回数据大小
None # 重叠IO结构(用于异步)
)
if result:
serial_number = out_buffer.value.decode('utf-8').strip('\\x00')
print(f"设备序列号是: {serial_number}")
else:
print(f"与设备通信失败,错误码: {ctypes.get_last_error()}")
# 6. 关闭设备句柄
kernel32.CloseHandle(hDevice)
这个过程就像是你(Python/Lua)给一位精通Windows内核的朋友(C语言扩展)写了一封详细的信。这位朋友带着你的请求,找到了正确的政府部门(DeviceIoControl)。政府内部经过流程(I/O管理器),将任务分配给具体的办事人员(设备驱动程序),最终由办事员完成对硬件(设备)的操作,并将结果原路返回给你。




