python 调⽤dll 三种⽅式
很早就开始⽤cython⽅法,ctype⽅法,最近知道还有个pythonnet⽅法。分别说来。1 cython 包海康sdk
根⽬录先放inc和lib ,分别是⼚商的.h⽂件和.so⽂件。然后根据头⽂件写cython的声明⽂件wrap.pyd:# -*- coding: UTF-8 -*-# -*- coding: UTF-8 -*-# cdef extern from "string.h":# void* memcpy(void* dest, void* src,size_t count) except +cdef extern from "HCNetSDK.h": ctypedef int BOOL ctypedef unsigned int DWORD ctypedef unsigned short WORD ctypedef unsigned short USHORT ctypedef short SHORT ctypedef int LONG ctypedef unsigned char BYTE ctypedef unsigned int UINT ctypedef void *LPVOID ctypedef void *HANDLE ctypedef unsigned int*LPDWORD ctypedef unsigned long long UINT64 ctypedef signed long long INT64 cdef enum : SERIALNO_LEN =48 NAME_LEN =32 MACADDR_LEN =6 COMM_ALARM =0x1100 #8000报警信息主动上传 MAX_DISKNUM =16#8000设备最⼤硬盘数 MAX_CHANNUM =16#8000设备最⼤通道数 MAX_ALARMOUT =4#8000设备最⼤报警输出数 ctypedef struct NET_DVR_DEVICEINFO_V30: BYTE sSerialNumber [SERIALNO_LEN ] BYTE byAlarmInPortNum BYTE byAlarmOutPortNum BYTE byDiskNum BYTE byDVRType BYTE byChanNum BYTE byStartChan BYTE byAudioChanNum BYTE byIPChanNum BYTE byZeroChanNum BYTE byMainProto BYTE bySubProto BYTE
bySupport BYTE bySupport1 BYTE bySupport2 WORD wDevType BYTE bySupport3 BYTE byMultiStreamProto BYTE byStartDChan BYTE byStartDTalkChan BYTE byHighDChanNum BYTE bySupport4 BYTE byLanguageType BYTE byVoiceInChanNum BYTE byStartVoiceInChanNo BYTE bySupport5 BYTE bySupport61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
WORD wStartMirrorChanNo BYTE bySupport7 BYTE byRes2 ctypedef struct NET_DVR_SDKSTATE : DWORD dwTotalLoginNum DWORD dwTotalRealPlayNum DWORD dwTotalPlayBackNum DWORD dwTotalAlarmChanNum DWORD dwTotalFormatNum DWORD dwTotalFileSearchNum DWORD dwTotalLogSearchNum DWORD dwTotalSerialNum DWORD dwTotalUpgradeNum DWORD dwTotalVoiceComNum DWORD dwTotalBroadCastNum DWORD dwTotalListenNum DWORD dwEmailTestNum DWORD dwBackupNum DWORD dwTotalInquestUploadNum DWORD dwRes [6] ctypedef NET_DVR_DEVICEINFO_V30 *LPNET_DVR_DEVICEINFO_V30 ctypedef NET_DVR_SDKSTATE *LPNET_DVR_SDKSTATE BOOL __stdcall NET_DVR_Init () except + BOOL __stdcall NET_DVR_Cleanup () except + BOOL __stdcall NET_DVR_SetConnectTime (DWORD dwWaitTime , DWORD dwTryTime ) except + BOOL __stdcall NET_DVR_SetReconnect (DWORD dwInterval , BOOL bEnableRecon ) except + DWORD __stdcall NET_DVR_GetLastError () except + LONG __stdcall NET_DVR_Login_V30(char *sDVRIP , WORD wDVRPort , char *sUserName , char *sPassword , LP
NET_DVR_DEVICEINFO_V30 lpDevice BOOL __stdcall NET_DVR_Logout_V30(LONG lUserID ) except + BOOL __stdcall NET_DVR_Logout (LONG lUserID ) except + BOOL NET_DVR_GetSDKState ( LPNET_DVR_SDKSTATE pSDKState ) except + ctypedef struct NET_DVR_ALARMER : BYTE byUserIDValid # userid 是否有效 0-⽆效,1-有效 */ BYTE bySerialValid # 序列号是否有效 0-⽆效,1-有效 */ BYTE byVersionValid # 版本号是否有效 0-⽆效,1-有效 */ BYTE byDeviceNameValid # 设备名字是否有效 0-⽆效,1-有效 */ BYTE byMacAddrValid # MAC 地址是否有效 0-⽆效,1-有效 */ BYTE byLinkPortValid # login 端⼝是否有效 0-⽆效,1-有效 */ BYTE byDeviceIPValid # 设备IP 是否有效 0-⽆效,1-有效 */ BYTE bySocketIPValid # socket ip 是否有效 0-⽆效,1-有效 */ LONG lUserID # NET_DVR_Login()返回值, 布防时有效 */ BYTE sSerialNumber [SERIALNO_LEN ]# /* 序列号 */ DWORD dwDeviceVersion # /* 版本信息 ⾼16位表⽰主版本,低16位表⽰次版本*/ char sDeviceName [NAME_LEN ]# /* 设备名字 */ BYTE byMacAddr [MACADDR_LEN ]# /* MAC 地址 */ WORD wLinkPort # link port */ char sDeviceIP [128]# /* IP 地址 */ char sSocketIP [128]# /* 报警主动上传时的socket IP 地址 */ BYTE byIpProtocol # /* Ip 协议 0-IPV4, 1-IPV6 */ BYTE byRes1[2] BYTE bJSONBroken # //JSON 断⽹续传标志。0:不续传;1:续传 WORD wSocketPort BYTE byRes2[6] ctypedef NET_DVR_ALARMER *LPNET_DVR_ALARMER ctypedef struct NET_DVR_ALARMINFO : DWORD dwAlarmType #/
*0-信号量报警,1-硬盘满,2-信号丢失,3-移动侦测,4-硬盘未格式化,5-读写硬盘出错,6-遮挡报警,7-制式不匹配, 8-⾮法访问, 9-视频
DWORD dwAlarmInputNumber #/*报警输⼊端⼝*/56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
⾃⼰设计到底⽤啥,写桥梁过度⽂件wrap.pyx: DWORD dwAlarmRelateChannel [MAX_CHANNUM ]#/*触发的录像通道,哪⼀位为1表⽰对应哪⼀路录像, dwAlarmRelateChannel[0]对应第1个通道*/ DWORD dwChannel [MAX_CHANNUM ]#/*dwAlarmType 为2或3,6,9,10时,表⽰哪个通道,dwChannel[0]位对应第1个通道*/ DWORD dwDiskNumber [MAX_DISKNUM ]#/*dwAlarmType 为1,4,5时,表⽰哪个硬盘, dwDiskNumber[0]位对应第1个硬盘*/ ctypedef NET_DVR_ALARMINFO *LPNET_DVR_ALARMINFO ctypedef void (__stdcall *MSGCallBack )(LONG lCommand , NET_DVR_ALARMER *pAlarmer , char *pAlarmInfo , DWORD dwBufLen , void * pUser ) BOOL __stdcall NET_DVR_SetDVRMessageCallBack_V30(MSGCallBack fMessageCallBack , void * pUser ) LONG __stdcall NET_DVR_StartListen_V30(char *sLocalIP , WORD wLocalPort , MSGCallBack DataCallback , void * pUserData ) BOOL __stdcall NET_DVR_StopListen_V30(LONG lListenHandle )
122
123
124
125
126
127
128
129
130
131
132
133cimport wrap from libc .stdlib cimport malloc , free from libc .string cimport memcpy from cpython .pycapsule cimport *# cdef object callbackfunc # cdef void __stdcall MessageCallback(LONG lCommand, NET_DVR_ALARMER *pAlarmer, char *pAlarmInfo, DWORD dwBufLen, void* pUser):# cdef wrap.NET_DVR_ALARMINFO struAlarmInfo # memcpy(&struAlarmInfo, pAlarmInfo, sizeof(wrap.NET_DVR_ALARMINFO))# altype=struAlarmInfo.dwAlarmType # chan=-1# for i in range(0,17):# if struAlarmInfo.dwCha
nnel[i] == 1:# chan=i+1# break # # 使⽤request 发送到sever # global callbackfunc # (<object>callbackfunc)(lCommand,altype,chan)# return cdef class Hc : cdef wrap .NET_DVR_DEVICEINFO_V30* struDeviceInfo cdef object callbackfunc # 这⾥不写,下⾯__init__要报错 def __cinit__(self ): self .struDeviceInfo = <wrap .NET_DVR_DEVICEINFO_V30*>malloc (sizeof (wrap .NET_DVR_DEVICEINFO_V30)) if not self .struDeviceInfo : raise MemoryError def __dealloc__(self ): free (self .struDeviceInfo ) def notify (self ,success ,what ): if success ==1: print (what +"success") else :print (what +"fail") return def __init__(self ): self .callbackfunc ="" def dvr_init (self ): success =wrap .NET_DVR_Init () self .notify (success ,"init") return def set_con_time (self ): success =wrap .NET_DVR_SetConnectTime (2000, 1) self .notify (success ,"set con time") return def set_recon_time (self ): success =wrap .NET_DVR_SetReconnect (10000, 1) self .notify (success ,"reset time")1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def get_error (self ): error_code =wrap .NET_DVR_GetLastError () return error_code def login_v30(self ,ip ,port ,user ,pwd ): userid =wrap .NET_DVR_Login_V30(ip ,port ,user ,pwd ,self .struDeviceInfo ) if userid <0: error_code =self .get_error () print ("login fail,error code:",error_code ) self .cleanup () print (self .struDeviceInfo .sSerialNumber ) return userid def logout_v30(self ,userid ): success =wrap .NET_DVR_Logout_V30(userid ) self .notify (success ,"logout") return def logout (self ,userid ): success =wrap .NET_DVR_Logout (userid ) self .notify (success ,"logout") return # 函数内部分配内存,free cpdef get_version (self ): cdef wrap .NET_DVR_SDKSTATE * psdkstate psdkstate =<wrap .NET_DVR_SDKSTATE *>malloc (sizeof (wrap .NET_DVR_SDKSTATE )) if not psdkstate : raise MemoryError success =wrap .NET_DVR_GetSDKState (psdkstate ) self .notify (success ,"get version") print (psdkstate .dwTotalLoginNum ) free (psdkstate ) return def cleanup (self ): success =wrap .NET_DVR_Cleanup () self .notify (success ,"clean up") return def stop_listen (self ,handler ): status =wrap .NET_DVR_StopListen_V30(handler ) return status # 在set callback 中把pyfunc 创建来,让他等于self 。callback ,真正的c callback 就是下⾯的中,运⾏pyfunc ,达到运⾏时传⼊函数控制的⽬的
cdef void __stdcall MessageCallback (self ,LONG lCommand , NET_DVR_ALARMER *pAlarmer , char *pAlarmInfo , DWORD dwBufLen , void * pUser cdef wrap .NET_DVR_ALARMINFO struAlarmInfo memcpy (&struAlarmInfo , pAlarmInfo , sizeof (wrap .NET_DVR_ALARMINFO )) altype =struAlarmInfo .dwAlarmType chan =-1 for i in range (0,17): if struAlarmInfo .dwChannel [i ] == 1: chan =i +1 break # 使⽤request 发送到sever (<object>self .callbackfunc )(lCommand ,altype ,chan ) return cpdef set_callback_listen (self ,pyfunc ,port ,lUserID ): # global callbackfunc self .callbackfunc =pyfunc wrap .NET_DVR_SetDVRMessageCallBack_V30(<wrap .MSGCallBack >self .MessageCallback , NULL ) lHandle = wrap .NET_DVR_StartListen_V30(NULL ,port , <wrap .MSGCallBack >self .MessageCallback , NULL ) if lHandle < 0: print ("NET_DVR_StartListen_V30 error code", self .get_error ()) self .logout (lUserID ) self .cleanup ()51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
python新手代码userid101
102
103
104
105
106
107
108
109
110
111
112
113
114
setup.py⽂件 python setup.py build_ext -i
最后是调⽤的例⼦116# -*- coding : utf -8 -*-from distutils .core import setup , Extension from Cython .Build import cythonize import os hccom = list (map (lambda x : x [3:-3], os .listdir ("./lib/HCNetSDKCom")))libs =["hcnetsdk", "HCCore", "ssl", "crypto", ":libcrypto.so.1.0.0"] + hccom print ("*********************************************************************")print (libs )setup ( ext_modules =cythonize ( Extension ( 'wrap',#mod name should be equal pyx file name ,so the file will be entrance sources =['wrap.pyx'], language ="c++", include_dirs =[os .path .abspath ("./inc")], library_dirs =[os .path .abspath ('.'), os .path .abspath ("./lib"),os .path .abspath ("./lib/HCNetSDKCom")], libraries =libs , extra_compile_args =[],
extra_link_args =[] ), compiler_directives ={'language_level': 3}, ))# build_ext --inplace # sources ⾥⾯可以包含 .pyx ⽂件,以及后⾯如果我们要调⽤ C/C++ 程序的话,还可以往⾥⾯加 .c / .cpp ⽂件# language 其实默认就是 c ,如果要⽤ C++,就改成 c++ 就好了# include_dirs 这个就是传给 gcc 的 -I 参数# library_dirs 这个就是传给 gcc 的 -L 参数# libraries 这个就是传给 gcc 的 -l 参数# extra_compile_args 就是传给 gcc 的额外的编译参数,⽐⽅说你可以传⼀个 -std=c++11# extra_link_args 就是传给 gcc 的额外的链接参数(也就是⽣成动态链接库的时候⽤的)# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib # export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib/HCNetSDKCom # etc 下有⼀个ld 的conf 可以增加 ldconfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论