Python开发调用DLL之ctypes初体验
-
在开发过程中不可避免涉及到与系统动态链接库的交互,在python如果需要实现调用系统动态链接库函数,必须使用ctypes模块。ctypes使用相对简单。
首先是dll的加载,windows下使用windll.LoadLibrary()函数。
第二是方法的调用,也很简单,可以直接 "对象.原方法名()”就可以了。如:<br /> self.carddll = windll.LoadLibrary("dcrf32.dll")<br /> self.icdev = self.carddll.dc_init(100,0)<br />
这里的dc_init()就是原来dll里的方法。
第三数据类型的转换,这是最复杂的,可以分为4种情况。
1.简单型(数值、字符、布尔)可以直接传递,不需要变化,比如上面的100,0 及其返回值icdev。
2.简单类型的指针。也较简单。分别有两种实现方法。
i.通过byref(参数)
ii.通过Pointer方法来构造一个指针变量如<br /> tempid = c_ulong(0)<br /> ptempid = pointer(tempid)<br /> st2 = self.carddll.dc_card(self.icdev, ModeALL, ptempid)<br />
<br /> tempid = c_ulong(0)<br /> st2 = self.carddll.dc_card(self.icdev, ModeALL, byref(tempid))<br />
以上两段代码等价
3.字符串,在dll中往往是char *类型。这里又分为两种情况.
i.如果传递方向是in很简单,直接把python中的字符串传入就可以了。
ii.如果是传递方向是out较复杂,需要构造一个字符串buffer,如:<br />readdata1 = create_string_buffer(16)<br />st3 = self.carddll.dc_read(self.icdev, Block8, readdata1)<br />readdata = readdata1.value[0:12]<br />
其中 readdata1就是读出的字符缓冲区,readdata是python字符串
4.结构体,较复杂需要用ctypes重性定义特殊格式的类。(本次开发没有涉及,就不深入了)
以下是完整的代码,通过threading.Thread类来实现多线程,通过多线程完成对射频的读取:<br />from ctypes import *<br />class DevWork(threading.Thread):<br /> "多线程实现读卡"<br /> def __init__(self,window):<br /> threading.Thread.__init__(self)<br /> self.window = window<br /> self._terminate=False<br /> #self.__suspend_lock = threading.Lock()<br /> <br /> def terminate(self):<br /> self._terminate = True<br /> <br /> <br /> def OpenDev(self):<br /> self.carddll = windll.LoadLibrary("dcrf32.dll")<br /> self.icdev = self.carddll.dc_init(100,0)<br /> if self.icdev <= 0 :<br /> return -1<br /> st = self.carddll.dc_load_key_hex(self.icdev,KEYSET0,Sec2,passwordA)<br /> if st != 0 :<br /> self.carddll.dc_exit(self.icdev)<br /> return -2<br /> return 1<br /> <br /> def run(self):<br /> <br /> tempid = c_ulong(0)<br /> ptempid = pointer(tempid)<br /> readdata1 = create_string_buffer(16)<br /> olddata = "a" * 12<br /> while True:<br /> time.sleep(3) <br /> if self._terminate:<br /> break<br /><br /> st2 = self.carddll.dc_card(self.icdev, ModeALL, ptempid)<br /> st2 = self.carddll.dc_authentication(self.icdev, KEYSET0, Sec2)<br /> st3 = self.carddll.dc_read(self.icdev, Block8, readdata1)<br /><br /> readdata = readdata1.value[0:12]<br /> if olddata == readdata: #同一张卡,不再操作<br /> continue<br /> else:<br /> self.window.Input(readdata)<br /> time.sleep(1)<br /> olddata = readdata<br /><br />
其中terminate()用来实现结束线程
OpenDev()用来打开设备
run()里边有个大循环,用来实现连续读取卡片内容。