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小时内删除。