Python手機開發呼叫DLL實現部分ADB功能

pythontab發表於2013-06-24

近期學了一點Python,然後正好有一個手機同步工具方面的預研工作要完成。

要實現PC與手機的通訊,首先要找到他們的通訊協議,還好的是Android有完善的協議:ADB

ADB的程式碼是開源的,而且支援Windows平臺,有現成的DLL可以呼叫:AdbWinApi.dll,AdbWinUsbApi.dll

好了,可以用VC搞定,但我想用Python試一下,於是開始了苦逼的查資料+實驗的過程。

實驗過程就不多說了,由於上面的兩個DLL都是用C實現的,提供的標頭檔案也是C語言的,所以有了下面這個python測試程式(Python2.7):

import ctypes 
  
#自定義的GUID結構,有興趣的可以自己研究用uuid模組  
class GUID(ctypes.Structure): 
    _fields_ = [("Data1", ctypes.c_ulong), 
                ("Data2", ctypes.c_ushort), 
                ("Data3", ctypes.c_ushort), 
                ("Data4", ctypes.c_ubyte*8)] 
  
#自己定義的一個結構體,便於使用DLL介面  
class AdbInterfaceInfo(ctypes.Structure): 
    _fields_ = [("class_id", GUID), 
                ("flags", ctypes.c_ulong), 
                ("device_name", ctypes.c_wchar*800)] 
  
def strGUID(GUID): 
    string = '' 
    string = string + '%x' % buff.class_id.Data1 + '-%x' % buff.class_id.Data2 + '-%x' % buff.class_id.Data3 
    string = string + '-%x' % buff.class_id.Data4[0] 
    string = string + '%x' % buff.class_id.Data4[1] 
    string = string + '%x' % buff.class_id.Data4[2] 
    string = string + '%x' % buff.class_id.Data4[3] 
    string = string + '%x' % buff.class_id.Data4[4] 
    string = string + '%x' % buff.class_id.Data4[5] 
    string = string + '%x' % buff.class_id.Data4[6] 
    string = string + '%x' % buff.class_id.Data4[7] 
    return string 
  
dll = ctypes.cdll.LoadLibrary('AdbWinApi.dll') 
usb_class_id = GUID(0xF72FE0D4, 0xCBCB, 0x407d, (0x88, 0x14, 0x9e, 0xd6, 0x73, 0xd0, 0xdd, 0x6b)) 
enum_handle = dll.AdbEnumInterfaces(usb_class_id, ctypes.c_bool('true'), ctypes.c_bool('true'), ctypes.c_bool('true')) 
  
while(1): 
    buff = AdbInterfaceInfo() 
    size = ctypes.c_ulong(ctypes.sizeof(buff)) 
    status = dll.AdbNextInterface(enum_handle, ctypes.byref(buff), ctypes.byref(size)) 
  
    if status==1: 
        #print "GUID = " + strGUID(buff.class_id)  
        #print "status = " + str(status)  
        #print "Name = " + str(buff.device_name)  
        hAdbApi = dll.AdbCreateInterfaceByName(buff.device_name); 
        if hAdbApi == 0: 
            print 'AdbCreateInterfaceByName Fail'
        else: 
            serial = ' '*128
            pserial = ctypes.c_char_p() 
            pserial.value = serial 
            serial_len = ctypes.c_ulong(len(serial)) 
            ret = dll.AdbGetSerialNumber(hAdbApi, pserial, ctypes.byref(serial_len), ctypes.c_bool('false')); 
            if ret == 1: 
                print 'Device Name: ' + '%s'% serial 
            else: 
                print 'Get Device Name Fail'
    else: 
        print 'Finished'
        break
import ctypes
#自定義的GUID結構,有興趣的可以自己研究用uuid模組
class GUID(ctypes.Structure):
    _fields_ = [("Data1", ctypes.c_ulong),
                ("Data2", ctypes.c_ushort),
                ("Data3", ctypes.c_ushort),
                ("Data4", ctypes.c_ubyte*8)]
#自己定義的一個結構體,便於使用DLL介面
class AdbInterfaceInfo(ctypes.Structure):
    _fields_ = [("class_id", GUID),
                ("flags", ctypes.c_ulong),
                ("device_name", ctypes.c_wchar*800)]
def strGUID(GUID):
    string = ''
    string = string + '%x' % buff.class_id.Data1 + '-%x' % buff.class_id.Data2 + '-%x' % buff.class_id.Data3
    string = string + '-%x' % buff.class_id.Data4[0]
    string = string + '%x' % buff.class_id.Data4[1]
    string = string + '%x' % buff.class_id.Data4[2]
    string = string + '%x' % buff.class_id.Data4[3]
    string = string + '%x' % buff.class_id.Data4[4]
    string = string + '%x' % buff.class_id.Data4[5]
    string = string + '%x' % buff.class_id.Data4[6]
    string = string + '%x' % buff.class_id.Data4[7]
    return string
dll = ctypes.cdll.LoadLibrary('AdbWinApi.dll')
usb_class_id = GUID(0xF72FE0D4, 0xCBCB, 0x407d, (0x88, 0x14, 0x9e, 0xd6, 0x73, 0xd0, 0xdd, 0x6b))
enum_handle = dll.AdbEnumInterfaces(usb_class_id, ctypes.c_bool('true'), ctypes.c_bool('true'), ctypes.c_bool('true'))
while(1):
    buff = AdbInterfaceInfo()
    size = ctypes.c_ulong(ctypes.sizeof(buff))
    status = dll.AdbNextInterface(enum_handle, ctypes.byref(buff), ctypes.byref(size))
    if status==1:
        #print "GUID = " + strGUID(buff.class_id)
        #print "status = " + str(status)
        #print "Name = " + str(buff.device_name)
        hAdbApi = dll.AdbCreateInterfaceByName(buff.device_name);
        if hAdbApi == 0:
            print 'AdbCreateInterfaceByName Fail'
        else:
            serial = ' '*128
            pserial = ctypes.c_char_p()
            pserial.value = serial
            serial_len = ctypes.c_ulong(len(serial))
            ret = dll.AdbGetSerialNumber(hAdbApi, pserial, ctypes.byref(serial_len), ctypes.c_bool('false'));
            if ret == 1:
                print 'Device Name: ' + '%s'% serial
            else:
                print 'Get Device Name Fail'
    else:
        print 'Finished'
        break


上面這個簡單的Python程式碼,可以透過AdbWinApi.dll和AdbWinUsbApi.dll這兩個DLL來找到你PC上正連線著的Android裝置。

只呼叫了3個DLL介面,但目的已經達到,可以得出下面的結論:

使用Python呼叫DLL的方式來實現ADB工具是可行的,當然麻煩是不會少的了。

寫在最後,Python呼叫C寫的DLL還是比較麻煩的,特別是引數傳遞,尤其是指標的處理,這方面還得依靠ctypes模組。。。


相關文章