简化python ctypes库调用API的封装

使用ctypes库调用C的函数, 需要进行封装. 如下所示:

# 对结构的封装
class STARTUPINFOEX(Structure):
    """ STARTUPINFOEX structure """
    _fields_ = [("StartupInfo", STARTUPINFO),
                ("lpAttributeList", POINTER(PVOID))]
# 对函数的封装
UpdateProcThreadAttribute = windll.kernel32.UpdateProcThreadAttribute
UpdateProcThreadAttribute.argtype = [
    POINTER(PVOID),
    DWORD,
    POINTER(DWORD),
    PVOID,
    SIZE_T,
    PVOID,
    POINTER(SIZE_T)
]
UpdateProcThreadAttribute.restype = BOOL

这个过程比较繁琐. 我做了一下优化, 简化使用场景如下:

CreatePipe = my_api.cdef('''
WINBASEAPI
BOOL
WINAPI
CreatePipe(
    _Out_ PHANDLE hReadPipe,
    _Out_ PHANDLE hWritePipe,
    _In_opt_ LPVOID lpPipeAttributes,
    _In_ DWORD nSize
    );
''')

用户只需要把C语言定义的函数描述拷贝下来, 剩下的封装工作就自动完成了.
结构也是同样的道理:

COORD,PCOORD = my_api.cdef('''
typedef struct _COORD {
    SHORT X;
    SHORT Y;
} COORD, *PCOORD;
''')

不仅如此, 通过访问函数或者结构的typing_notion属性, 可以自动生成类型注解相关的代码, 如下所示:

def CreatePipe(hReadPipe:PHANDLE,hWritePipe:PHANDLE,lpPipeAttributes:LPVOID,nSize:DWORD)->BOOL:pass
CreatePipe = my_api.cdef('''
WINBASEAPI
BOOL
WINAPI
CreatePipe(
    _Out_ PHANDLE hReadPipe,
    _Out_ PHANDLE hWritePipe,
    _In_opt_ LPVOID lpPipeAttributes,
    _In_ DWORD nSize
    );
''')

print(CreatePipe.typing_notion)
# 输出: def CreatePipe(hReadPipe:PHANDLE,hWritePipe:PHANDLE,lpPipeAttributes:LPVOID,nSize:DWORD)->BOOL:pass

这样就可以享受类型注解的好处了(比如代码自动补全), 同时也不影响函数的功能.

posted @ 2024-03-19 10:50  顺其自然,道法自然  阅读(44)  评论(0编辑  收藏  举报