您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 经营企划 > Python 调用DLL文件
Python调用windows下DLL详解原文URL是貌似原文的网页服务器有问题,总是load不全,所以备个份:Python调用windows下DLL详解在python中某些时候需要C做效率上的补充,在实际应用中,需要做部分数据的交互。使用python中的ctypes模块可以很方便的调用windows的dll(也包括linux下的so等文件),下面将详细的讲解这个模块(以windows平台为例子),当然我假设你们已经对windows下怎么写一个DLL是没有问题的。引入ctypes库fromctypesimport*假设你有了一个符合cdecl(这里强调调用约定是因为,stdcall调用约定和cdecl调用约定声明的导出函数,在用python加载使用的加载函数是不同的,后面会说明)调用约定的DLL(名字是add.dll),且有一个导出函数Add。建立一个Python文件DllCall.py测试:fromctypesimport*dll=CDLL(add.dll)printdll.Add(1,102)结果:103上面是一个简单的例子。1、加载DLL上面已经说过,加载的时候要根据你将要调用的函数是符合什么调用约定的。stdcall调用约定:两种加载方式Objdll=ctypes.windll.LoadLibrary(dllpath)Objdll=ctypes.WinDLL(dllpath)cdecl调用约定:也有两种加载方式Objdll=ctypes.cdll.LoadLibrary(dllpath)Objdll=ctypes.CDLL(dllpath)其实windll和cdll分别是WinDLL类和CDll类的对象。2、调用dll中的方法在1中加载dll的时候会返回一个DLL对象(假设名字叫Objdll),利用该对象就可以调用dll中的方法。e.g.如果dll中有个方法名字叫Add(注意如果经过stdcall声明的方法,如果不是用def文件声明的导出函数的话,编译器会对函数名进行修改,这个要注意)调用:nRet=Objdll.Add(12,15)即完成一次调用。看起来调用似乎很简单,不要只看表象,呵呵,这是因为Add这个函数太简单了,现在假设函数需要你传入一个int类型的指针(int*),可以通过库中的byref关键字来实现,假设现在调用的函数的第三个参数是个int类型的指针。intPara=c_int(9)dll.sub(23,102,byref(intPara))printintPara.value如果是要传入一个char缓冲区指针,和缓冲区长度,方法至少有四种:#char*--1szPara=create_string_buffer('\0'*100)dll.PrintInfo(byref(szPara),100);printszPara.value#char*--2sBuf='aaaaaaaaaabbbbbbbbbbbbbb'pStr=c_char_p()pStr.value=sBuf#pVoid=ctypes.cast(pStr,ctypes.c_void_p).valuedll.PrintInfo(pStr,len(pStr.value))printpStr.value#char*--3strMa=\0*20FunPrint=dll.PrintInfoFunPrint.argtypes=[c_char_p,c_int]#FunPrint.restypes=c_void_pnRst=FunPrint(strMa,len(strMa))printstrMa,len(strMa)#char*--4pStr2=c_char_p(\0)printpStr2.value#pVoid=ctypes.cast(pStr,ctypes.c_void_p).valuedll.PrintInfo(pStr2,len(pStr.value))printpStr2.value3、C基本类型和ctypes中实现的类型映射表ctypes数据类型C数据类型c_charcharc_shortshortc_intintc_longlongc_ulongunsignlongc_floatfloatc_doubledoublec_void_pvoid对应的指针类型是在后面加上_p,如int*是c_int_p等等。在python中要实现c语言中的结构,需要用到类。4、DLL中的函数返回一个指针。虽然这不是个好的编程方法,不过这种情况的处理方法也很简单,其实返回的都是地址,把他们转换相应的python类型,在通过value属性访问。pchar=dll.getbuffer()szbuffer=c_char_p(pchar)printszbuffer.value5、处理C中的结构体类型为什么把这个单独提出来说呢,因为这个是最麻烦也是最复杂的,在python里面申明一个类似c的结构体,要用到类,并且这个类必须继承自Structure。先看一个简单的例子:C里面dll的定义如下:typedefstruct_SimpleStruct{intnNo;floatfVirus;charszBuffer[512];}SimpleStruct,*PSimpleStruct;typedefconstSimpleStruct*PCSimpleStruct;externCint__declspec(dllexport)PrintStruct(PSimpleStructsimp);intPrintStruct(PSimpleStructsimp){printf(nMaxNum=%f,szContent=%s,simp-fVirus,simp-szBuffer);returnsimp-nNo;}Python的定义:fromctypesimport*classSimpStruct(Structure):_fields_=[(nNo,c_int),(fVirus,c_float),(szBuffer,c_char*512)]dll=CDLL(AddDll.dll)simple=SimpStruct();simple.nNo=16simple.fVirus=3.1415926simple.szBuffer=magicTong\0printdll.PrintStruct(byref(simple))上面例子结构体很简单,如果结构体里面有指针,甚至是指向结构体的指针,python里面也有相应的处理方法。下面这个例子来自网上,本来想自己写个,懒得写了,能说明问题就行:C代码如下:typedefstruct{charwords[10];}keywords;typedefstruct{keywords*kws;unsignedintlen;}outStruct;externCint__declspec(dllexport)test(outStruct*o);inttest(outStruct*o){unsignedinti=4;o-kws=(keywords*)malloc(sizeof(unsignedchar)*10*i);strcpy(o-kws[0].words,TheFirstData);strcpy(o-kws[1].words,TheSecondData);o-len=i;return1;}Python代码如下:classkeywords(Structure):_fields_=[('words',c_char*10),]classoutStruct(Structure):_fields_=[('kws',POINTER(keywords)),('len',c_int),]o=outStruct()dll.test(byref(o))printo.kws[0].words;printo.kws[1].words;printo.len6、例子说得天花乱坠,嘿嘿,还是看两个实际的例子。例子一:这是一个GUID生成器,其实很多第三方的python库已经有封装好的库可以调用,不过这得装了那个库才行,如果想直接调用一些API,对于python来说,也要借助一个第三方库才行,这个例子比较简单,就是用C++调用win32API来产生GUID,然后python通过调用c++写的dll来获得这个GUIDC++代码如下:externC__declspec(dllexport)char*newGUID();char*newGUID(){staticcharbuf[64]={0};statcGUIDguid;if(S_OK==::CoCreateGuid(&guid)){//%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X_snprintf(buf,sizeof(buf),%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X,guid.Data1,guid.Data2,guid.Data3,guid.Data4[0],guid.Data4[1],guid.Data4[2],guid.Data4[3],guid.Data4[4],guid.Data4[5],guid.Data4[6],guid.Data4[7]);::MessageBox(NULL,buf,GUID,MB_OK);}return(char*)buf;}Python代码如下:defCreateGUID():创建一个全局唯一标识符类似:E06093E2-699A-4BF2-A325-4F1EADB50E18NewVersiontry:#dllpathstrDllPath=sys.path[0]+str(os.sep)+createguid.dlldll=CDLL(strDllPath)b=dll.newGUID()a=c_char_p(b)exceptException,error:printerrorreturnreturna.value例子二:这个例子是调用kernel32.dll中的createprocessA函数来启动一个记事本进程。#-*-coding:utf-8-*-fromctypesimport*#定义_PROCESS_INFORMATION结构体class_PROCESS_INFORMATION(Structure):_fields_=[('hProcess',c_void_p),('hThread',c_void_p),('dwProcessId',c_ulong),('dwThreadId',c_ulong)]#定义_STARTUPINFO结构体class_STARTUPINFO(Structure):_fields_=[('cb',c_ulong),('lpReserved',c_char_p),('lpDesktop',c_char_p),('lpTitle',c_char_p),('dwX',c_ulong),('dwY',c_ulong),('dwXSize',c_ulong),('dwYSize',c_ulong),('dwXCountChars',c_ulong),('dwYCountChars',c_ulong),('dwFillAttribute',c_ulong),('dwFlags',c_ulong),('wShowWindow',c_ushort),('cbReserved2',c_ushort),('lpReserved2',c_char_p),('hStdInput',c_ulong),('hStdOutput',c_ulong),('hStdError',c_ulong)]NORMAL_PRIORITY_CLASS=0x00000020#定义NORMAL_PRIO
本文标题:Python 调用DLL文件
链接地址:https://www.777doc.com/doc-4210002 .html