merge changes from the 0.1 preparatio branch
[totalopenstation.git] / scanwin32.py
blob9e9a06d6447c1bea461f10dc5d16019b9bb3711a
1 import ctypes
2 import re
4 def ValidHandle(value):
5 if value == 0:
6 raise ctypes.WinError()
7 return value
9 NULL = 0
10 HDEVINFO = ctypes.c_int
11 BOOL = ctypes.c_int
12 CHAR = ctypes.c_char
13 PCTSTR = ctypes.c_char_p
14 HWND = ctypes.c_uint
15 DWORD = ctypes.c_ulong
16 PDWORD = ctypes.POINTER(DWORD)
17 ULONG = ctypes.c_ulong
18 ULONG_PTR = ctypes.POINTER(ULONG)
19 #~ PBYTE = ctypes.c_char_p
20 PBYTE = ctypes.c_void_p
22 class GUID(ctypes.Structure):
23 _fields_ = [
24 ('Data1', ctypes.c_ulong),
25 ('Data2', ctypes.c_ushort),
26 ('Data3', ctypes.c_ushort),
27 ('Data4', ctypes.c_ubyte*8),
29 def __str__(self):
30 return "{%08x-%04x-%04x-%s-%s}" % (
31 self.Data1,
32 self.Data2,
33 self.Data3,
34 ''.join(["%02x" % d for d in self.Data4[:2]]),
35 ''.join(["%02x" % d for d in self.Data4[2:]]),
38 class SP_DEVINFO_DATA(ctypes.Structure):
39 _fields_ = [
40 ('cbSize', DWORD),
41 ('ClassGuid', GUID),
42 ('DevInst', DWORD),
43 ('Reserved', ULONG_PTR),
45 def __str__(self):
46 return "ClassGuid:%s DevInst:%s" % (self.ClassGuid, self.DevInst)
47 PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA)
49 class SP_DEVICE_INTERFACE_DATA(ctypes.Structure):
50 _fields_ = [
51 ('cbSize', DWORD),
52 ('InterfaceClassGuid', GUID),
53 ('Flags', DWORD),
54 ('Reserved', ULONG_PTR),
56 def __str__(self):
57 return "InterfaceClassGuid:%s Flags:%s" % (self.InterfaceClassGuid, self.Flags)
58 PSP_DEVICE_INTERFACE_DATA = ctypes.POINTER(SP_DEVICE_INTERFACE_DATA)
60 PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p
62 SetupDiDestroyDeviceInfoList = ctypes.windll.setupapi.SetupDiDestroyDeviceInfoList
63 SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO]
64 SetupDiDestroyDeviceInfoList.restype = BOOL
66 SetupDiGetClassDevs = ctypes.windll.setupapi.SetupDiGetClassDevsA
67 SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD]
68 SetupDiGetClassDevs.restype = ValidHandle #HDEVINFO
70 SetupDiEnumDeviceInterfaces = ctypes.windll.setupapi.SetupDiEnumDeviceInterfaces
71 SetupDiEnumDeviceInterfaces.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, ctypes.POINTER(GUID), DWORD, PSP_DEVICE_INTERFACE_DATA]
72 SetupDiEnumDeviceInterfaces.restype = BOOL
74 SetupDiGetDeviceInterfaceDetail = ctypes.windll.setupapi.SetupDiGetDeviceInterfaceDetailA
75 SetupDiGetDeviceInterfaceDetail.argtypes = [HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA, DWORD, PDWORD, PSP_DEVINFO_DATA]
76 SetupDiGetDeviceInterfaceDetail.restype = BOOL
78 SetupDiGetDeviceRegistryProperty = ctypes.windll.setupapi.SetupDiGetDeviceRegistryPropertyA
79 SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD]
80 SetupDiGetDeviceRegistryProperty.restype = BOOL
83 GUID_CLASS_COMPORT = GUID(0x86e0d1e0L, 0x8089, 0x11d0,
84 (ctypes.c_ubyte*8)(0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73))
86 DIGCF_PRESENT = 2
87 DIGCF_DEVICEINTERFACE = 16
88 INVALID_HANDLE_VALUE = 0
89 ERROR_INSUFFICIENT_BUFFER = 122
90 SPDRP_HARDWAREID = 1
91 SPDRP_FRIENDLYNAME = 12
92 ERROR_NO_MORE_ITEMS = 259
94 def comports(available_only=True):
95 """This generator scans the device registry for com ports and yields port, desc, hwid.
96 If available_only is true only return currently existing ports."""
97 flags = DIGCF_DEVICEINTERFACE
98 if available_only:
99 flags |= DIGCF_PRESENT
100 g_hdi = SetupDiGetClassDevs(ctypes.byref(GUID_CLASS_COMPORT), None, NULL, flags);
101 #~ for i in range(256):
102 for dwIndex in range(256):
103 did = SP_DEVICE_INTERFACE_DATA()
104 did.cbSize = ctypes.sizeof(did)
106 if not SetupDiEnumDeviceInterfaces(
107 g_hdi,
108 None,
109 ctypes.byref(GUID_CLASS_COMPORT),
110 dwIndex,
111 ctypes.byref(did)
113 if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS:
114 raise ctypes.WinError()
115 break
117 dwNeeded = DWORD()
118 # get the size
119 if not SetupDiGetDeviceInterfaceDetail(
120 g_hdi,
121 ctypes.byref(did),
122 None, 0, ctypes.byref(dwNeeded),
123 None
125 # Ignore ERROR_INSUFFICIENT_BUFFER
126 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
127 raise ctypes.WinError()
128 # allocate buffer
129 class SP_DEVICE_INTERFACE_DETAIL_DATA_A(ctypes.Structure):
130 _fields_ = [
131 ('cbSize', DWORD),
132 ('DevicePath', CHAR*(dwNeeded.value - ctypes.sizeof(DWORD))),
134 def __str__(self):
135 return "DevicePath:%s" % (self.DevicePath,)
136 idd = SP_DEVICE_INTERFACE_DETAIL_DATA_A()
137 idd.cbSize = 5
138 devinfo = SP_DEVINFO_DATA()
139 devinfo.cbSize = ctypes.sizeof(devinfo)
140 if not SetupDiGetDeviceInterfaceDetail(
141 g_hdi,
142 ctypes.byref(did),
143 ctypes.byref(idd), dwNeeded, None,
144 ctypes.byref(devinfo)
146 raise ctypes.WinError()
148 # hardware ID
149 szHardwareID = ctypes.create_string_buffer('\0' * 250)
150 if not SetupDiGetDeviceRegistryProperty(
151 g_hdi,
152 ctypes.byref(devinfo),
153 SPDRP_HARDWAREID,
154 None,
155 ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1,
156 None
158 # Ignore ERROR_INSUFFICIENT_BUFFER
159 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
160 raise ctypes.WinError()
162 # friendly name
163 szFriendlyName = ctypes.create_string_buffer('\0' * 250)
164 if not SetupDiGetDeviceRegistryProperty(
165 g_hdi,
166 ctypes.byref(devinfo),
167 SPDRP_FRIENDLYNAME,
168 None,
169 ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1,
170 None
172 # Ignore ERROR_INSUFFICIENT_BUFFER
173 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
174 raise ctypes.WinError()
175 port_name = re.search(r"\((.*)\)", szFriendlyName.value).group(1)
176 if len(port_name) > 4:
177 port_name = '\\\\.\\'+port_name
178 yield port_name, szFriendlyName.value, szHardwareID.value
180 SetupDiDestroyDeviceInfoList(g_hdi)
183 if __name__ == '__main__':
184 import serial
185 for port, desc, hwid in comports():
186 print "%s: %s (%s)" % (port, desc, hwid)
187 print " "*10, serial.Serial(port) #test open
189 # list of all ports the system knows
190 print "-"*60
191 for port, desc, hwid in comports(False):
192 print "%-10s: %s (%s)" % (port, desc, hwid)