利用python3的ctypes庫實現動態庫so的調用

 

核心關注點在於通過python來處理C函數的入參與出參

 

一、動態庫編譯(C語言):

#ifdef _WIN_

#define DllExport   __declspec( dllexport )

#else

#define DllExport   __attribute ((visibility("default")))

#endif


DllExport int lookup(BYTE *in, WORD in_len, DWORD dwStartBit, BYTE *out, DWORD *out_len, BYTE bDir,  CHAR *key)

二、導出符號表(eg:Linux):

nm -D look.so

在符號表中,可以看到第一步中C語言的導出函數。

三、出參處理(BYTE *out):

Python 默認的 string 是不可變的,所以不能傳遞 string 到一個 C 函數去改變它的內容,所以需要使用 create_string_buffer,對應 Unicode 字符串,要使用 create_unicode_buffer,

C常規參數類型與ctypes、python類型對應關係表如下:

四、實例源碼:

#! /usr/bin/env/python
# _*_ encoding : utf-8 _*_
 
from ctypes import *
import platform
import os, re


def getSpace(level):
    space='\n'
    for i in range(level):
        space=space+'    '
    return space

# 格式化 XML 字符串#
def printXml(xml_str):
    
    #xml_list=xml_str.split('([>])')
    new_xml_list=""
    # head=xml_str[0:9]
    # xml_str=xml_str[9:]
    xml_list=re.split(r'([>])',xml_str)
    xml_list = ["".join(i) for i in zip(xml_list[0::2],xml_list[1::2])]
    level=0
    for node in xml_list:
        if(re.match(r'<\?xml .*version.*\?>',node)):
            new_xml_list=new_xml_list+new_xml_list+node
            continue
        elif(re.match(r'<[^\?^/].*[^/]>',node)):
            new_xml_list=new_xml_list+getSpace(level)+node
            level=level+1
            continue
        elif(re.match(r'</.*[^/]>',node)):
            level=level-1
            new_xml_list=new_xml_list+getSpace(level)+node
            continue
        elif(re.match(r'<[^/].*/>',node)):
            new_xml_list=new_xml_list+getSpace(level)+node
        elif(re.match(r'.+</.*[^/]>',node)):
            new_xml_list=new_xml_list+node
            level=level-1
        else:
            print(node)

    # print(new_xml_list)
    return new_xml_list


def writeXML(outputstrt, xmlFileName):
	fileHandle = open(xmlFileName, 'w',encoding="utf_8_sig")
	fileHandle.write('')
	fileHandle.close()

	fileHandle = open(xmlFileName, 'a',encoding="utf_8_sig")
	fileHandle.write(outputstrt + '\n\n')
	fileHandle.close()



if __name__ == '__main__':
    # key = "123456789" # 暫時隨便寫一個
    # key_str = "E7 AB 8B E6 B0 91 E5 9B BD E4 BB AC E6 88 91 E4 B8 AD E4 BA BA E4 B8 BA E4 BA 86 E5 BB BA E4 B8" # 暫時隨便寫一個
    key_str = '07 41 01 08 49 06 11 99 09 20 00 00 05 F3 72 40 30 00 00 05 52 00 D0 11 D1'
    bitstream_Str = '01 00 01 38 00 00 00 00 12 00 30 10 80 08 64 10 91 99 00 32 11 F2 02 01 05 83 01 01'

    # 輸入碼流的預處理
    input_len = len(bitstream_Str.replace(" ", '')) // 2
    bitstream_list = bitstream_Str.split(' ')
    input = (c_char * input_len)()
    for i in range(input_len):
        input[i] = int(bytes(bitstream_list[i], encoding='utf-8'),16)
        print(int(bytes(bitstream_list[i], encoding='utf-8'),16))
    in_p = bytes(bytearray(input))

    key_len = len(key_str.replace(" ", '')) // 2
    key_list = key_str.split(' ')
    key = (c_char * key_len)()
    for i in range(key_len):
        key[i] = int(bytes(key_list[i], encoding='utf-8'),16)
        print(int(bytes(key_list[i], encoding='utf-8'),16))
    key_p = bytes(bytearray(key))



    # 打開 .so 文件
    sotest = cdll.LoadLibrary(os.getcwd()+ "/XML.so")
    sotest.argtypes = [c_char_p, c_ushort, c_uint, c_ubyte, c_uint, c_ubyte, c_ubyte, c_ubyte, c_char_p, c_char_p, c_ubyte, c_char_p] # 聲明C函數的所有入參
    sotest.restype=[c_int]                # 聲明C函數的返回值類型
    buffer  = create_string_buffer(8000000) # 創建可用於修改的出參
    buffer_len = c_int()                  # 定義出參的長度變量

    print("\n--------------------------------so打印結果輸出-------------------------------------\n")
    result = sotest.PubDecode(in_p,        #BYTE *in
                        input_len,            #WORD in_len
                        0,                    #DWORD dwStartBit+
                        9,                    #BYTE bModType
                        1325056,              #DWORD msgType             
                        3,                    #BYTE msgVersion                     
                        0,                    #BYTE bDir       1 - receive      0 - send
                        0,                    #BYTE bNetType
                        buffer,               #BYTE *out
                        byref(buffer_len),    # DWORD *out_len
                        0,                    #BYTE isAnony
                        key_p)                #CHAR *key

    print("\n--------------------------------py調試結果輸出-------------------------------------\n")
    print(os.getcwd()+ "/XML.so")
    print("\n******--------input--------******")
    print("input_len: " + str(input_len))
    print("bitstream_Str: " + bitstream_Str.replace(" ", ''))
    print(in_p)
    print(bitstream_list)
    print("\n******--------result--------******")
    print("result: %d    0-ok 1-failed" % result)
    print("\n******--------output--------******")
    print("out_len: " + str(buffer_len.value))
    print("\n------------------")
    print(str(buffer.value).replace(r'\n', '').replace(r'\r', '').split("'")[1])
    print("\n--------------------------------結果輸出到文件-------------------------------------\n")
    writeXML(printXml(str(buffer.value).replace(r'\n', '').replace(r'\r', '').split("'")[1]), 'xmlpcode.txt')

 

五、reference:

python調用第三方動態庫(附代碼) - 官方文檔
https://blog.csdn.net/chongtong/article/details/81566868

Python調用DLL動態鏈接庫——ctypes使用
https://www.cnblogs.com/FHC1994/p/11421229.html

Python調用c/c++動態庫(一)
https://blog.csdn.net/giveaname/article/details/89811783

python調用C/C++程序出現的32位和64位的問題
https://blog.csdn.net/budding0828/article/details/89344888

Python利用ctypes實現按引用傳參
https://www.cnblogs.com/douzujun/p/10822031.html

Python實例淺談之三Python與C/C++相互調用
https://www.cnblogs.com/apexchu/p/5015961.html

python在 linux上調用.so文件
https://blog.csdn.net/python_tty/article/details/44495659

python關於ctypes使用char指針與bytes相互轉換的問題
https://www.cnblogs.com/hjbf/p/11969521.html

Python中bytes與字符串的相互轉化
https://www.cnblogs.com/haitaoli/p/10587257.html

Python工作筆記-往dll中傳入char*類型的參數並且如何接收char*的值 - 利用了ctypes庫中的string_at
https://blog.csdn.net/qq78442761/article/details/83058756

使用 ctypes 進行 Python 和 C 的混合編程
https://www.cnblogs.com/gaowengang/p/7919219.html

將博客搬至CSDN —— python 調用 so 庫 需要注意的地方
https://blog.csdn.net/github_37157365/article/details/80494733

通過ctype由python向C語言傳遞char *,獲取新結果
https://blog.csdn.net/weixin_38825407/article/details/101709466

python調用c/c++ (入參出參爲指針)
https://www.cnblogs.com/taurusfy/p/9321883.html

https://www.cnblogs.com/kgtone/p/9601918.html
任務備忘(已經完成):用python寫一個格式化xml字符串的程序

Python字符串前面加u,r,b的含義
https://blog.csdn.net/winfred_hua/article/details/86079353

格式化XML字符串

https://www.cnblogs.com/kgtone/p/9601918.html

發佈了143 篇原創文章 · 獲贊 58 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章