python调用C语言API, 一般使用内置的ctypes库. 但是这个库用起来不那么方便, 主要是需要进行函数和数据结构的包装. 如下所示:
# 结构定义
class COORD(Structure):
""" COORD structure """
_fields_ = [("X", SHORT),
("Y", SHORT)]
# 函数定义
UpdateProcThreadAttribute = windll.kernel32.UpdateProcThreadAttribute
UpdateProcThreadAttribute.argtype = [
POINTER(PVOID),
DWORD,
POINTER(DWORD),
PVOID,
SIZE_T,
PVOID,
POINTER(SIZE_T)
]
UpdateProcThreadAttribute.restype = BOOL
UpdateProcThreadAttribute.errcheck = _errcheck_bool
这是一个比较大的工作量, 也很不方便.
有一个cffi库, 可以简化这个过程. 使用示例如下:
from cffi import FFI
ffi = FFI()
# 定义需要使用的Windows API函数和结构
ffi.cdef("""
BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe,
LPVOID lpPipeAttributes, DWORD nSize);
BOOL WriteFile(HANDLE hFile, const void *lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPVOID lpOverlapped);
BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPVOID lpOverlapped);
BOOL CloseHandle(HANDLE hObject);
""")
# 加载kernel32.dll
kernel32 = ffi.dlopen("kernel32.dll")
# 创建管道的句柄
read_handle = ffi.new("PHANDLE")
write_handle = ffi.new("PHANDLE")
# 创建管道
if not kernel32.CreatePipe(read_handle, write_handle, ffi.NULL, 0):
raise OSError("Failed to create pipe")
# 写入管道
message = b"Hello, pipe!"
bytes_written = ffi.new("LPDWORD")
if not kernel32.WriteFile(write_handle[0], message, len(message), bytes_written, ffi.NULL):
raise OSError("Failed to write to pipe")
# 从管道读取
buffer = ffi.new("char[1024]")
bytes_read = ffi.new("DWORD[1]")
if not kernel32.ReadFile(read_handle[0], buffer, len(buffer), bytes_read, ffi.NULL):
raise OSError("Failed to read from pipe")
# 输出读取到的数据
print(ffi.string(buffer, bytes_read[0]).decode())
# 关闭句柄
kernel32.CloseHandle(read_handle[0])
kernel32.CloseHandle(write_handle[0])
补充说明:
ffi.cdef
函数声明C函数原型, windows的常见类型, 比如HANDLE
,LPVOID
,DWORD
等已经事先定义好了, 对于额外的数据结构需要额外定义.- 函数原型可以直接查看<windows.h>相关文件定义, 拷贝过来即可.
CFFI库相关参考
网址: https://github.com/python-cffi/cffi
相关文档: https://cffi.readthedocs.io/en/stable/using.html