Python调用C/C++动态链接库的方法详解
本文以实例讲解了Python调用C/C++DLL动态链接库的方法,具体示例如下:
示例一:
首先,在创建一个DLL工程(本例创建环境为VS2005),头文件:
//hello.h
#ifdefEXPORT_HELLO_DLL
#defineHELLO_API__declspec(dllexport)
#else
#defineHELLO_API__declspec(dllimport)
#endif
extern"C"
{
HELLO_APIintIntAdd(int,int);
}
CPP文件:
//hello.cpp
#defineEXPORT_HELLO_DLL
#include"hello.h"
HELLO_APIintIntAdd(inta,intb)
{
returna+b;
}
这里有两个注意点:
(1)弄清楚编译的时候函数的调用约定采用的__cdecl还是__stdcall,因为根据DLL中函数调用约定方式,Python将使用相应的函数加载DLL。
(2)如果采用C++的工程,那么导出的接口需要extern"C",这样python中才能识别导出的函数。
我的工程中采用__cdecl函数调用约定方式进行编译链接产生hello.dll,然后Python中采用ctypes库对hello.dll进行加载和函数调用:
fromctypesimport*
dll=cdll.LoadLibrary('hello.dll');
ret=dll.IntAdd(2,4);
printret;
至此,第一个小例子已经完成了,读者可以自己动手尝试一下运行效果。
示例二:
示例一只是一个"helloworld"级别的程序,实际运用中更多的需要传递数据结构、字符串等,才能满足我们的需求。那么本示例将展示,如何传递数据结构参数,以及如何通过数据结构获取返回值。
首先编写DLL工程中的头文件:
//hello.h
#ifdefEXPORT_HELLO_DLL
#defineHELLO_API__declspec(dllexport)
#else
#defineHELLO_API__declspec(dllimport)
#endif
#defineARRAY_NUMBER20
#defineSTR_LEN20
structStructTest
{
intnumber;
char*pChar;
charstr[STR_LEN];
intiArray[ARRAY_NUMBER];
};
extern"C"
{
//HELLO_APIintIntAdd(int,int);
HELLO_APIchar*GetStructInfo(structStructTest*pStruct);
}
CPP文件如下:
//hello.cpp
#include<string.h>
#defineEXPORT_HELLO_DLL
#include"hello.h"
HELLO_APIchar*GetStructInfo(structStructTest*pStruct)
{
for(inti=0;i<ARRAY_NUMBER;i++)
pStruct->iArray[i]=i;
pStruct->pChar="hellopython!";
strcpy(pStruct->str,"helloworld!");
pStruct->number=100;
return"justOK";
}
GetStructInfo这个函数通过传递一个StructTest类型的指针,然后对对象中的属性进行赋值,最后返回"justOK".
编写Python调用代码如下,首先在Python中继承Structure构造一个和CDLL中一致的数据结构StructTest,然后设置函数GetStructInfo的参数类型和返回值类型,最后创建一个StructTest对象,并将其转化为指针作为参数,调用函数GetStrcutInfo,最后通过输出数据结构的值来检查是否调用成功:
fromctypesimport*
ARRAY_NUMBER=20;
STR_LEN=20;
#definetype
INTARRAY20=c_int*ARRAY_NUMBER;
CHARARRAY20=c_char*STR_LEN;
#definestruct
classStructTest(Structure):
_fields_=[
("number",c_int),
("pChar",c_char_p),
("str",CHARARRAY20),
("iArray",INTARRAY20)
]
#loaddllandgetthefunctionobject
dll=cdll.LoadLibrary('hello.dll');
GetStructInfo=dll.GetStructInfo;
#setthereturntype
GetStructInfo.restype=c_char_p;
#settheargtypes
GetStructInfo.argtypes=[POINTER(StructTest)];
objectStruct=StructTest();
#invokeapiGetStructInfo
retStr=GetStructInfo(byref(objectStruct));
#checkresult
print"number:",objectStruct.number;
print"pChar:",objectStruct.pChar;
print"str:",objectStruct.str;
fori,valinenumerate(objectStruct.iArray):
print'Array[i]:',val;
printretStr;
总结:
1.用64位的Python去加载32位的DLL会出错
2.以上只是些测试程序,在编写Python过程中尽可能的使用"tryExcept"来处理异常
3.注意在Python与CDLL交互的时候字节对齐问题
4.ctypes库的功能还有待继续探索