在Python中使用Win32 IPHelper API的问题

2 投票
3 回答
2061 浏览
提问于 2025-04-16 04:33

我正在尝试创建一个Python模块,用来获取网络参数。我使用了ctypes,但遇到了一些问题。

函数 __getInterfaces_win2k() 在Python 2.5和2.6中可以正常工作,但在Python 2.7中就不行了(出现了未处理的异常,错误信息是:在python.exe的0x1e001759处发生访问冲突,读取位置0x00000010)。

函数 __getInterfaces_win_after_win2k() 在任何版本的Python中都无法工作(同样的错误)。

有时候,在程序崩溃之前,它会打印出一些必要的信息。我几乎尝试比较了所有与C语言程序的值,结果都是正常的。非常感谢任何帮助。

'''
    Get different network parameters (interfaces, routing table, etc)
'''

from platform import system
from sys import getwindowsversion

def getInterfaces():
    if system() == 'Windows':
        winversion = getwindowsversion() 
        #from table on page OSVERSIONINFO Structure for GetVersionEx Function
        if winversion[0] > 5 or (winversion[0] == 5 and winversion[1] > 0):
            return __getInterfaces_win_after_win2k()
        else:
            return __getInterfaces_win2k()
    else:
        pass

MAX_ADAPTER_ADDRESS_LENGTH = 8

def __getInterfaces_win_after_win2k():
    import ctypes.wintypes

    class HEADER_STRUCT(ctypes.Structure):
        _fields_ = [
            ("Length", ctypes.c_ulong),
            ("IfIndex", ctypes.c_ulong)]

    class HEADER_UNION(ctypes.Union):
        _fields_ = [
            ("Alignment", ctypes.c_ulonglong),
            ("HEADER_STRUCT", HEADER_STRUCT)]

    class SOCKADDR(ctypes.Structure):
        _fields_ = [
            ("sa_family", ctypes.c_ushort),
            ("sa_data", ctypes.c_byte * 14)]
    PSOCKADDR = ctypes.POINTER(SOCKADDR)

    class SOCKET_ADDRESS(ctypes.Structure):
        _fields_ = [
            ("pSockaddr", PSOCKADDR),
            ("iSockaddrLength", ctypes.c_int)]

    class IP_ADAPTER_UNICAST_ADDRESS(ctypes.Structure):
        pass
    PIP_ADAPTER_UNICAST_ADDRESS = ctypes.POINTER(IP_ADAPTER_UNICAST_ADDRESS)
    IP_ADAPTER_UNICAST_ADDRESS._fields_ = [
        ("length", ctypes.c_ulong),
        ("flags", ctypes.c_ulong),
        ("next", PIP_ADAPTER_UNICAST_ADDRESS),
        ("address", SOCKET_ADDRESS),
        ("prefixOrigin", ctypes.c_int),
        ("suffixOrigin", ctypes.c_int),
        ("dadState", ctypes.c_int),
        ("validLifetime", ctypes.c_ulong),
        ("preferredLifetime", ctypes.c_ulong),
        ("leaseLifetime", ctypes.c_ulong),
        ("onLinkPrefixLength", ctypes.c_byte)]

    class IP_ADAPTER_ANYCAST_ADDRESS(ctypes.Structure):
        pass
    PIP_ADAPTER_ANYCAST_ADDRESS = ctypes.POINTER(IP_ADAPTER_ANYCAST_ADDRESS)
    IP_ADAPTER_ANYCAST_ADDRESS._fields_ = [
        ("alignment", ctypes.c_ulonglong),
        ("next", PIP_ADAPTER_ANYCAST_ADDRESS),
        ("address", SOCKET_ADDRESS)]

    class IP_ADAPTER_MULTICAST_ADDRESS(ctypes.Structure):
        pass
    PIP_ADAPTER_MULTICAST_ADDRESS = ctypes.POINTER(IP_ADAPTER_MULTICAST_ADDRESS)
    IP_ADAPTER_MULTICAST_ADDRESS._fields_ = [
        ("alignment", ctypes.c_ulonglong),
        ("next", PIP_ADAPTER_MULTICAST_ADDRESS),
        ("address", SOCKET_ADDRESS)]

    class IP_ADAPTER_DNS_SERVER_ADDRESS(ctypes.Structure):
        pass
    PIP_ADAPTER_DNS_SERVER_ADDRESS = ctypes.POINTER(IP_ADAPTER_DNS_SERVER_ADDRESS)
    IP_ADAPTER_DNS_SERVER_ADDRESS._fields_ = [
        ("alignment", ctypes.c_ulonglong),
        ("next", PIP_ADAPTER_DNS_SERVER_ADDRESS),
        ("address", SOCKET_ADDRESS)]

    class IP_ADAPTER_PREFIX(ctypes.Structure):
        pass
    PIP_ADAPTER_PREFIX = ctypes.POINTER(IP_ADAPTER_PREFIX)
    IP_ADAPTER_PREFIX._fields_ = [
        ("alignment", ctypes.c_ulonglong),
        ("next", PIP_ADAPTER_PREFIX),
        ("address", SOCKET_ADDRESS),
        ("prefixLength", ctypes.c_ulong)]

    class IP_ADAPTER_WINS_SERVER_ADDRESS(ctypes.Structure):
        pass
    PIP_ADAPTER_WINS_SERVER_ADDRESS = ctypes.POINTER(IP_ADAPTER_WINS_SERVER_ADDRESS)
    IP_ADAPTER_WINS_SERVER_ADDRESS._fields_ = [
        ("alignment", ctypes.c_ulonglong),
        ("next", PIP_ADAPTER_WINS_SERVER_ADDRESS),
        ("address", SOCKET_ADDRESS)]

    class IP_ADAPTER_GATEWAY_ADDRESS(ctypes.Structure):
        pass
    PIP_ADAPTER_GATEWAY_ADDRESS = ctypes.POINTER(IP_ADAPTER_GATEWAY_ADDRESS)
    IP_ADAPTER_GATEWAY_ADDRESS._fields_ = [
        ("alignment", ctypes.c_ulonglong),
        ("next", PIP_ADAPTER_GATEWAY_ADDRESS),
        ("address", SOCKET_ADDRESS)]

    #ifdef.h
    class NET_LUID(ctypes.Structure):
        _fields_ = [
            ("value", ctypes.c_ulonglong)]

    class GUID(ctypes.Structure):
        _fields_ = [
            ("data1", ctypes.wintypes.DWORD),
            ("data2", ctypes.wintypes.WORD),
            ("data3", ctypes.wintypes.WORD),
            ("data4", ctypes.c_byte * 8)]

    MAX_DNS_SUFFIX_STRING_LENGTH = 256
    class IP_ADAPTER_DNS_SUFFIX(ctypes.Structure):
        pass
    PIP_ADAPTER_DNS_SUFFIX = ctypes.POINTER(IP_ADAPTER_DNS_SUFFIX)
    IP_ADAPTER_DNS_SUFFIX._fields_ = [
        ("next", PIP_ADAPTER_DNS_SUFFIX),
        ("string", ctypes.c_wchar * MAX_DNS_SUFFIX_STRING_LENGTH)]

    class IP_ADAPTER_ADDRESSES(ctypes.Structure):
        pass
    PIP_ADAPTER_ADDRESSES = ctypes.POINTER(IP_ADAPTER_ADDRESSES)
    MAX_DHCPV6_DUID_LENGTH = 130 #IPTypes.h
    IP_ADAPTER_ADDRESSES._fields_ = [
        ("header", HEADER_UNION),
        ("next", PIP_ADAPTER_ADDRESSES),
        ("adapterName", ctypes.c_char_p),
        ("firstUnicastAddress", PIP_ADAPTER_UNICAST_ADDRESS),
        ("firstAnycastAddress", PIP_ADAPTER_ANYCAST_ADDRESS),
        ("firstMulticastAddress", PIP_ADAPTER_MULTICAST_ADDRESS),
        ("firstDnsServerAddress", PIP_ADAPTER_DNS_SERVER_ADDRESS),
        ("dnsSuffix", ctypes.c_wchar_p),
        ("description", ctypes.c_wchar_p),
        ("friendlyName", ctypes.c_wchar_p),
        ("physicalAddress", ctypes.c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("physicalAddressLength", ctypes.wintypes.DWORD),
        ("flags", ctypes.wintypes.DWORD),
        ("mtu", ctypes.wintypes.DWORD),
        ("ifType", ctypes.wintypes.DWORD),
        ("operStatus", ctypes.c_int),
        ("ipv6IfIndex", ctypes.wintypes.DWORD),
        ("zoneIndices", ctypes.wintypes.DWORD * 16),
        ("firstPrefix", PIP_ADAPTER_PREFIX),
        ("transmitLinkSpeed", ctypes.c_ulonglong),
        ("receiveLinkSpeed", ctypes.c_ulonglong),
        ("firstWinsServerAddress", PIP_ADAPTER_WINS_SERVER_ADDRESS),
        ("firstGatewayAddress", PIP_ADAPTER_GATEWAY_ADDRESS),
        ("ipv4Metric", ctypes.c_ulong),
        ("ipv6Metric", ctypes.c_ulong),
        ("luid", NET_LUID),#ifdef.h
        ("dhcpv4Server", SOCKET_ADDRESS),
        ("compartmentId", ctypes.c_uint32),#ifdef.h
        ("networkGuid", GUID),
        ("connectionType", ctypes.c_int),
        ("tunnelType", ctypes.c_int),
        ("dhcpv6Server", SOCKET_ADDRESS),
        ("dhcpv6ClientDuid", ctypes.c_byte * MAX_DHCPV6_DUID_LENGTH),
        ("dhcpv6ClientDuidLength", ctypes.c_ulong),
        ("dhcpv6Iaid", ctypes.c_ulong)]

    GetAdaptersAddresses = ctypes.windll.iphlpapi.GetAdaptersAddresses
    GetAdaptersAddresses.restype = ctypes.c_ulong
    GetAdaptersAddresses.argtypes = [
        ctypes.c_ulong, ctypes.c_ulong, ctypes.c_void_p,
        PIP_ADAPTER_ADDRESSES, ctypes.POINTER(ctypes.c_ulong)]

    outBufLen = ctypes.c_ulong(15000)
    adapters = ctypes.pointer(IP_ADAPTER_ADDRESSES())
    ctypes.resize(adapters, outBufLen.value)

    from socket import AF_INET
    GAA_FLAG_INCLUDE_PREFIX = ctypes.c_ulong(0x0010)

    GetAdaptersAddresses(ctypes.c_ulong(AF_INET), GAA_FLAG_INCLUDE_PREFIX, None,
                         adapters, ctypes.byref(outBufLen))

    a = adapters[0]
    ifaces = {}
    while a:
        iface = {}

        iface['desc'] = a.description

#        iface['mac'] = ':'.join(["%02X" % part for part in a.address])
#                  
#        adNode = a.ipAddressList
#        iface['ip'] = []
#        while True:
#            ipAddr = adNode.ipAddress
#            if ipAddr:
#                iface['ip'].append( (ipAddr, adNode.ipMask) )
#            if adNode.next:
#                adNode = adNode.next.contents
#            else:
#                break

        ifaces[a.adapterName] = iface

        if a.next:
            a = a.next.contents
        else:
            break


    return ifaces    

def __getInterfaces_win2k():
    import ctypes.wintypes

    MAX_ADAPTER_NAME_LENGTH = 256
    MAX_ADAPTER_DESCRIPTION_LENGTH = 128

    class IP_ADDR_STRING(ctypes.Structure):
        pass
    LP_IP_ADDR_STRING = ctypes.POINTER(IP_ADDR_STRING)
    IP_ADDR_STRING._fields_ = [
        ("next", LP_IP_ADDR_STRING),
        ("ipAddress", ctypes.c_char * 16),
        ("ipMask", ctypes.c_char * 16),
        ("context", ctypes.wintypes.DWORD)]

    class IP_ADAPTER_INFO (ctypes.Structure):
        pass
    LP_IP_ADAPTER_INFO = ctypes.POINTER(IP_ADAPTER_INFO)
    IP_ADAPTER_INFO._fields_ = [
        ("next", LP_IP_ADAPTER_INFO),
        ("comboIndex", ctypes.wintypes.DWORD),
        ("adapterName", ctypes.c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
        ("description", ctypes.c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
        ("addressLength", ctypes.c_uint),
        ("address", ctypes.c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("index", ctypes.wintypes.DWORD),
        ("type", ctypes.c_uint),
        ("dhcpEnabled", ctypes.c_uint),
        ("currentIpAddress", LP_IP_ADDR_STRING),
        ("ipAddressList", IP_ADDR_STRING),
        ("gatewayList", IP_ADDR_STRING),
        ("dhcpServer", IP_ADDR_STRING),
        ("haveWins", ctypes.c_uint),
        ("primaryWinsServer", IP_ADDR_STRING),
        ("secondaryWinsServer", IP_ADDR_STRING),
        ("leaseObtained", ctypes.c_ulong),
        ("leaseExpires", ctypes.c_ulong)]

    GetAdaptersInfo = ctypes.windll.iphlpapi.GetAdaptersInfo
    GetAdaptersInfo.restype = ctypes.wintypes.DWORD
    GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, ctypes.POINTER(ctypes.c_ulong)]

    adapters = ctypes.pointer(IP_ADAPTER_INFO())
    buflen = ctypes.c_ulong(ctypes.sizeof(IP_ADAPTER_INFO))
    GetAdaptersInfo(adapters, ctypes.byref(buflen))

    ctypes.resize(adapters, buflen.value)
    GetAdaptersInfo(adapters, ctypes.byref(buflen))

    a = adapters.contents
    ifaces = {}
    while a:
        iface = {}

        iface['desc'] = a.description

        iface['mac'] = ':'.join(["%02X" % part for part in a.address])

        adNode = a.ipAddressList
        iface['ip'] = []
        while True:
            ipAddr = adNode.ipAddress
            if ipAddr:
                iface['ip'].append( (ipAddr, adNode.ipMask) )
            if adNode.next:
                adNode = adNode.next.contents
            else:
                break

        ifaces[a.adapterName] = iface

        if a.next:
            a = a.next.contents
        else:
            break


    return ifaces

if __name__ == "__main__":
    ifaces = getInterfaces()
    for k, v in ifaces.iteritems():
        print k
        for k2, v2 in v.iteritems():
            print '\t', k2, v2

3 个回答

0

你可以在这个链接找到适用于Windows网络的ctypes Python功能:http://code.google.com/p/pywingui/source/browse/#svn/trunk/pywingui/network。另外,这里有一些示例:http://code.google.com/p/pywingui/source/browse/#svn/trunk/pywingui_tests

0

我找不到关于Python版本变化导致ctypes字节大小变化的任何信息,但我遇到了一个问题,涉及到IP_ADAPTER_INFO结构和time_t的大小。

解决方案可以在这里找到 http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/fe17ff48-71e4-401b-9982-84addb809eea

所以也许可以把这些代码行

("leaseObtained", ctypes.c_ulong) 
("leaseExpires", ctypes.c_ulong)

改成

("leaseObtained", ctypes.c_uint)
("leaseExpires", ctypes.c_uint)
0

我不知道这是不是你问题的原因,但NET_LUID结构的最后一个字段好像缺失了:一个64位的“Info”结构。另外,IP_ADAPTER_ADDRESSES结构的最后一个字段(FirstDnsSuffix)也缺失了,不过这只在W2k8服务器上才重要——我猜你是在Vista或XP上使用这段代码。

撰写回答