1625-5 王子昂 总结《2017年8月10日》 【连续第312天总结】
A. RouterScan-Python封装
B.
在老师的指导下验证了ScanRouter的参数应该是结构体的指针,而不是句柄;
那么封装可以通过构造一个相同的结构体传入来完成,但是原程序得到结果的方法为Print_GUI,即直接通过句柄打印在界面中
但是作者在exc文件夹下提供了封装的demo,PASCAL的源代码,参考可以发现动态链接库中提供了回调函数的设置
还有直接没明白的大量setParam参数,都在其中有详细的文档说明
不过由于python和C的变量类型还是有大量不同,在传入参数时需要细细甄别、多加尝试,所以还是卡了挺久
首先,PrepareRouter传入四个参数,分别为Dword row,ip ;Word port; THandle hRouter,其中最麻烦的是hRouter,本以为它就是结构体的指针,但其实只是一个 缓冲区,其中存放的值才是结构体的指针
然后ScanRouter传入hRouter的值,作为结构体的指针
最恐怖的是Pascal中两处传参完全相同,纠结了好几个小时为什么ip和port存不进hRouter,幸亏昨天OD逆出过这点,吃饭的时候休息才想起来,原来是存进了hRouter指向的结构体里。
明白这点以后就比较轻松了,通过py3的int.from_bytes()方法将hRouter的指针转为int,送入ScanRouter中即可
hRouter=create_string_buffer(b'1',40)
if(dll.PrepareRouter(1,ip.value,port.value,hRouter)!=0):
print("PrepareSuccess")
hRouter=int.from_bytes(hRouter.raw[:4],byteorder='little',signed=False)
else:
print("PrepareFailed")
if(dll.ScanRouter(hRouter)!=0):
print("ScanSuccess")
else:
print("ScanFailed")
那么,最关键的返回值怎么办呢
从Pascal的源码中可以看出,setParamW的第3项的值就是回调函数的指针;传参有3个,分别是row,name和value
Python的回调函数指针需要使用ctypes库中提供的CFUNTYPE;
注意CFUNCTYPE()工厂函数使用cdecl调用约定创建回调函数的类型(在Win上,WINFUNCTYPE()工厂函数使用stdcall调用约定创建回调函数的类型)
callbackFunc = WINFUNCTYPE(None, c_int32, c_wchar_p, c_wchar_p)
callbackf = callbackFunc(callback)
dll.SetParamW(stSetTableDataCallback,callbackf)
注意:callbackf变量尽量避免放在函数内,如果作为局部变量,那么它的作用域就只有函数内,当该函数结束时callbackf将被清除,使得真正回调的时候指针失效而出错;因此作为全局变量是最稳妥的
CFUNCTYPE和WINFUNCTYPE都将第一个参数作为返回值的类型,其后依次写参数类型即可
总体来说坑主要就是类型的转换,没有文档的情况下复用太困难了OTZ
得到很大帮助的参考链接:
ctypes学习笔记http://git.oschina.net/explict/codes/zq0nhvlfm6gyeo4ducpsi90
C. 明日计划
ZigBee协议栈