【Python】Windows平台调用DLL中的方法
一、前言
我有一次在用Python开发项目工具的时候,需要用到一个加解密的模块。但是这个模块是纯C实现的,而且也是项目自己实现的算法,不可能有现成的Python库可以使用,当然我也不能用Python再写一遍。因此就想用Python调用C的接口,通过面向搜索引擎编程,找到了Python可以使用ctypes调用dll的方法,经过一番折腾后成功搞定。本篇文章特此记录一下之前学习的内容。
二、开始
首先需要有一个DLL文件,如名为encrypt.dll
的DLL文件,里面包含的接口定义在下面。然后我们开始一步步完成加载dll文件,并调用其中的方法。
// 创建一个加密解密对象, 通过传入的密钥 encrypt_obj* create(int key); // 使用加密对象进行加密文本 void do_encrypt(encrypt_obj* obj, char* text, int size); // 使用解密对象进行解密 void do_decrypt(encrypt_obj* obj, char* btext, int size);
1. 加载dll
一个简单的加载dll的代码如下:
import ctypes encrypt_dll = ctypes.CDLL("encrypt.dll")
我们知道dll的接口有stdcall和cdecl两种调用约定,因此ctypes加载dll也有两种方式:
# stdcall std_dll = ctypes.windll.LoadLibrary("dll") std_dll = ctypes.WinDLL("dll") # cdecl cd_dll = ctypes.cdll.LoadLibrary("dll") cd_dll = ctypes.CDLL("dll")
2.调用传参
完成第一步的dll加载后,会返回这个dll的对象,现在我们就可以调用里面的方法了,例如:encrypt_dll.create(1)
。
调用方法参数传递时,分基本类型和指针类型。基本的类型例如: int、float、char、short 这些都可以直接调用传入参数。但如果是指针类型,例如int*,就需要做一下转化,具体如下:
# 先创建一个int的对象 int_v = ctypes.c_int(1) # 然后调用byref 作为指针传入方法中 dll.func(ctypes.byref(int_v))
另外参数为char* 时,调用的代码如下:
# 1. 创建字符串 pstr = ctypes.c_char_p("string text") # 或者 pstr = ctypes.c_char_p() pstr.value = "string text" # 2.然后调用传参 dll.func(ctypes.byref(pstr))
如果既需要传入参数,也需要获取方法执行的返回值,而且不想像上面那样进行几步操作的话,可以使用下面的方式。在一开始就显示的定义好dll中的每个方法的传入参数类型,返回参数类型。这样就可以更方便的进行方法调用了。
# 先声明dll的这个方法的传入参数和返回值类型 encrypt_dll.create.argtypes = [c_int] encrypt_dll.create.restypes = c_void_p # 这样就可以直接调用 obj = encrypt_dll.create(1) # 只定义传入参数类型,不定义返回值类型 encrypt_dll.do_encrypt.argtypes=[c_void_p,c_char_p,c_int] # 定义好参数类型后,就可以直接传入参数了。 encrypt_dll.do_encrypt(obj, "aaa", 3)
3. C基本类型和ctypes中类型映射表
c_char |
char |
c_short |
short |
c_int |
int |
c_long |
long |
c_ulong |
unsigned long |
c_float |
float |
c_double |
double |
c_void_p |
void* |
针对表格前面7个,如果是指针类型时,就是在对应的类型后面加上"_p"。例如char* 就是c_char_p, int* 就是 c_int_p 等。
4. 处理结构体
如果有时候需要使用C的结构体,例如做一些赋值,读取数据的操作,这个时候就需要在Python中定义一个C的结构体类。以下是简单的一个例子。
// C语言中的结构体 typedef struct _myStruct { int nValue; char szBuffer[128]; } MyStruct;
# Python中实现 import ctypes class MyStruct(ctypes.Structure): """ 继承自Structure """ _fields_ = [ ("nValue", ctypes.c_int), ("szBuffer", ctypes.c_char * 128)] # 调用方式如下 dll = ctypes.CDLL("sample.dll") my = MyStruct() my.nValue = 123123 my.szBuffer = "string text" dll.callfunc(ctypes.byref(my))
三、总结
以上就是Python中调用Windows中的dll的方法,根据上面的方法我们就可以与C进行交互了,是不是很简单呢?希望看后对大家有帮助!
欢迎微信搜索"游戏测试开发"关注一起沟通交流。