python3调dll库复盘
对c程序员来说,写python简直就是打开了一片新天地。
首先要确认下动态库文件是32位的还是64位,python程序要对应。
先定义一个类loaddll来封装dll库里对应接口函数,一般提供dll库的人都会提供一个.h文件,我们参考这个头文件来封装对应的函数。
加载dll文件
import ctypes class loaddll(): def __init__(self): try: self.dll = ctypes.cdll.LoadLibrary('dcltd.dll') print('load ok') except Exception as e: print(e)
根据头文件中的内容,继续在类loaddll添加函数,函数名字可一样,可不一样。假设头文件中有这样一个函数
bool DCLTInit(int maxnodes);
有一个int型数据入参,返回值是布尔型。那这些都要做对应的转换,对应的python代码如下
def DCLTInit(self, maxnodes): try: self.dll.DCLTInit.restype = ctypes.c_bool self.dll.DCLTInit.argtype = ctypes.c_int result = self.dll.DCLTInit(int(maxnodes)) if result: print('init function ok') else: print('error') except Exception as e: print(e)
restype表示返回值类型,ctypes.c_bool是c类型的布尔;argtype表示的入参类型,如果是多个入参,比如两个,整形和char*,argtypes = (ctypes.c_int,c_char_p)。如下面这个例子
def BCAddNode(self, ip, port): try: self.dll.DCAddNode.restype = ctypes.c_int self.dll.DCAddNode.argtypes = (ctypes.c_char_p, ctypes.c_int) c_ip = ctypes.c_char_p() c_ip.value = ip.encode('gbk') no = self.dll.DCAddNode(c_ip, int(port)) return no except Exception as e: print(e)
接下来写个demo测试下:
hdll = loaddll() hdll.DCLTInit(1) no = hdll.DCAddNode('10.243.141.16', 5800) print(no)
运行结果:
load ok
init function ok
0
Process finished with exit code 0
上面这些一切都是很美好,直到遇到了int*做入参的函数,即即使入参又是出参。在c程序中因为没有引用,想传一个地址,并且这个地址的值在函数内被修改,就比较喜欢用指针。
def DCGetRetCode(self, handle, icode): try: self.dll.DCGetRetCode.restype = ctypes.c_bool self.dll.DCGetRetCode.argtypes = [ctypes.c_void_p, ctypes.c_void_p] # self.bcc.DCGetRetCode.argtype = ctypes.c_void_p code = icode code = ctypes.c_int() b = pointer(code) # b是code的地址 bRet = self.dll.DCGetRetCode(ctypes.c_void_p(handle), byref(code)) ''' self.dll.DCGetRetCode(ctypes.c_void_p(handle), ctypes.pointer(code)) 用这种方式返回的code不是具体的int数值,而是c_long(100),在数值外面有c_long code.value的值居然是0,醉了 百思不得其解 网上查到到用value都能得到类型里面的值 但这里就是不行 byref表示传引用 返回值b[0]就是取指针地址值 ''' return bret, b[0] except Exception as e: print(e)
调这个函数方法如下
code = -1
bret, code = hdll.DCGetRetCode(handle, code)
如果是c++类库的话,就得另想办法。