前一篇讲了简单的C/C++调用Python脚本模块(.py)。既然是用于诸多游戏程序的脚本语言,那肯定是缺不了互调(礼尚往来)。因此,本篇讲一个简单的python调用C/C++写的DLL模块,对Python进行功能扩展。这里写一个简单的例子,主要就为了了解下这么用Python来调用C/C++写的DLL库。好了,切入正题:

 首先,我是用VS2003建的一个DLL工程,将DLL工程属性里面的输出文件的(.dll)改为(.pyd)。当然也可以将生成后的DLL扩展名改为.pyd。呵呵!免得大家以为它很神秘(VC还能生成.pyd库?这种疑问!)好,直接贴代码:

代码例子

#include <Python.h>

 

int processTestCmd( const char *arg )
{
     int n = system( arg );
     return n;
}


static PyObject * MyCCallFuncName( PyObject *self, PyObject *args )
{
     const char * command;
     if ( !PyArg_ParseTuple( args, "s", &command ) )
          return NULL;

     int n = processTestCmd( command );
     return Py_BuildValue( "i", n );
}


static PyMethodDef PythonCallMethods[] =         //注册python可以调用的C方法
{
     { "MyPythonUseFuncName", MyCCallFuncName, METH_VARARGS, "Execute a shell command." },        //第一个参数python调用的函数名字,第二个则是我们C/C++方法
     { NULL, NULL, 0, NULL } 
};


PyMODINIT_FUNC initMyPythonCallModule( void )
{
     PyObject *m = Py_InitModule( "MyPythonCallModule", PythonCallMethods ); //第一个参数是我们C/C++编译出来的pyd模块,第二个参数为注册给python脚本可以调用的方法数组
     if (m == NULL)

         return;
}

 

解析: 

(1)包裹函数wrap_cmd_fun。它负责将Python的参数转化为C的参数(PyArg_ParseTuple),调用实际的processCmd进行逻辑处理,最终返回把C/C++函数的返回值进行处理再给Python环境。 
(2)导出表PythonCallMethods。它负责告诉Python这个模块里有哪些函数可以被Python调用。导出表的名字可以随便起,

每一项有4 个参数:第一个参数是提供给Python环境的函数名称,

第二个参数是C/C++函数,即包裹函数。

第三个参数的含义是参数变长,

第四个 参数是一个说明性的字符串。导出表总是以{NULL, NULL, 0, NULL}结束。 
(3)导出函数initMyPythonCallModule。这个的名字不是任取的,是你的module名称添加前缀init。导出函数中将模块名称与导出表进行连接。
------------------

首先是Py_InitModule用于初始化在Python脚本中要import的模块,这里的模块名是:MyPythonCallModule。我们在Python中将使用import MyPythonCallModule 来载入这个模块。

这里我们将PythonCallMethods作为模块要调用的方法,它是一个PyMethodDef结构。我们可以看到这个结构的数组定义,{ "MyPythonUseFuncName", MyCCallFuncName, METH_VARARGS, "Execute a shell command." },

红色的就是我们在脚本里面要调用的函数名字,它被映射为C/C++的函数:MyCCallFuncName,当在Python脚本中调用MyPythonUseFuncName时将会调用MyCCallFuncName函数。

第三个METH_VARARGS成员表示调用方式,可以用或运算连接几个调用方式。

第四个成员是一个方法的说明,这里说明他是一个用来执行控制台命令的。

数组的第二个元素{ NULL, NULL, 0, NULL } 表示函数列表结束,结束就用NULL。言外之意就是我们可以再这个结构数组中映射多个C/C++函数用于python来调用。

MyCCallFuncName函数就不用我来解释了,就是将Python调用时传进来的参数转化成字符串,然后调用processTestCmd函数,返回值是整型,又传回给python程序。

给出一个格式化时的"i", "s"之类的Python脚本类型说明表:

 

格式化字符

C数据类型

Python类型

s

char*

字符串

s#

char*, int

字符串及长度

z

char*

s相同,但可以为NULL

 

续表

 

 

格式化字符

C数据类型

Python类型

z#

char*, int

s#相同,但可以为NULL

i

int

长整型

l

long int

长整型

c

char

单个字符的字符串

f

float

双精度型

d

double

双精度型

 好了,我们开始编译,编译出来的库文件为:MyFirstPythonModule.pyd

之后我们写Python脚本:

import MyFirstPythonModule                                  #引用库文件。
input = MyFirstPythonModule.MyPythonUseFuncName( "mkdir" )  #调用函数,传入得是dir命令。
print input                                                              #将返回值打印出来。

好了!就这么简单。之所以用CC++模块的形式,是为了提高Python脚本的性能,也是为了交互。更多的好处还得在使用中得以体现。