在Python语言中,可以使用ctypes模块调用其他用C++语言编写的动态链接库DLL文件中的函数。在提高软件运行效率的同时,还可以充分利用目前市面上的各种第三方DLL库函数,从而扩展Python软件的功能和应用领域,减少重复编写代码和重复造轮子的工作量,充分体现了Python语言作为胶水语言的独特优势。
这一次我们就用一个具体的例子来谈谈如何在Python中使用ctypes模块调用DLL中的库函数。本文的编程系统环境是win7 64位,Python使用python2.7.14。

由于DLL中函数传递的参数类型多种多样,我们打算分三次解释这一部分。这次我们先讲传数值、指针和字符串参数,然后分两次讲解传结构和数值数组的类型。
DLL文件的加载
假设已经有一个dll文件“MyDll.dll”,其函数由C调用,Python中加载Dll文件的代码如下:
其中,第一行介绍了ctypes模块,第二行使用C调用约定加载“MyDll.dll”文件,并将返回值赋给Dll变量,该变量将用于定义后面调用dll文件中的函数时要使用的具体函数。
另外,需要注意的是,如果DLL函数的调用约定是标准的调用约定,那么DLL文件的加载代码就改为如下:
dll = WinDLL
DLL的调用-当函数参数是数值时
例如,对于“MyDll.dll”文件中的函数add,其函数语句如下:
该函数有两个int输入参数x和y,以及两个返回数字的和。C语言的实现代码如下:
Python中的调用模式如下:
这个功能应该说是最简单的一个。第17行,直接使用第一步加载dll后返回的名称DLL,后面跟着函数名返回它的值。
DLL函数的调用-当函数参数是指针时
对于上述函数改进为add2,其函数C语言实现代码如下:
此时,函数有三个指针参数x,y,z指向int类型,z是x和y的和。

Python中的调用模式如下:
其中,第20-22行定义了三个int变量X、Y和Z,初始值分别为2、3和0。第23行,调用add2函数时,用byref表示参数传递是引用传递,对应C语言中的指针传递。函数运行后,使用z.value查看z的值。
您也可以使用下面的代码来调用:
在上面的代码中,第23-24行,使用add2函数时,先将函数赋给一个变量add2,然后分别声明它的输入输出参数,用POINTER声明这三个参数是指向int类型的指针变量。
当函数参数是字符串时调用DLL
示例:对于下面的函数,返回一个输入字符串的字节长度,其函数C语言的实现代码如下:
Python中的调用代码如下:
其中,第33行使用c_char_p定义了一个指向char类型的指针变量pStr,初始值为‘abcdef’。在第34行,它被传递给GetStringLength函数以返回它的长度。
也可以用以下代码调用它:
GetStringLength函数的输入和输出参数分别使用argtypes和restype声明。
2:比如下面这个函数,输入输出都是字符串指针。函数的作用是将值“StrIn”赋给输入pStr1,并将指向字符串常量“strOut”的指针返回给输出。函数C语言的实现代码如下:
Python中的调用代码如下:
在上述代码中,I/O参数也是单独声明的。对于输入参数pStr,使用create_string_buffer函数定义一个stringbuffer区域。对于返回值pChar,在打印输出结果时,强制转换为c_char_p类型,取其值即可。
完整的测试代码

完整的测试代码如下图所示:
操作结果如下图所示:
摘要
这个例子基本上涵盖了在Python中通过ctypes模块调用DLL函数时传递数值、指针和字符串类型参数的大多数情况。注意,在C语言中使用ctypes映射数据类型时,两者必须完全相同。下面是Python的ctypes模块中的数据类型和C语言中的数据类型的对比表:
欢迎关注,一起交流。


