Creating choose folder-dialog from Python using Windows API - python

I'm trying to create a choose folder-dialog from Python, but I'm having problems setting the initial folder path for the dialog. I think it's a problem converting the string to a LPARAM when I'm setting the _BROWSEINFO structure.
bi.lParam = cast(path.encode("ascii", "ignore"), POINTER(LPARAM)).contents
I'm getting this error in the callback:
windll.user32.SendMessageA(handle, _BFFM_SETSELECTIONA, 1, lpdata)
ctypes.ArgumentError: argument 4: <class 'OverflowError'>: int too long to convert
Below is the code I'm using, it seems to work well except the call to SendMessageA.
I'm setting the _BROWSEINFO structure in browse_folder,
_WM_USER = 0x400
_BFFM_INITIALIZED = 1
_BFFM_SETSELECTIONA = _WM_USER + 102
_BFFM_SETSELECTIONW = _WM_USER + 103
_BIF_RETURNONLYFSDIRS = 0x00000001
_BIF_NEWDIALOGSTYLE = 0x00000040
_BFFCALLBACK = WINFUNCTYPE(None, HWND, UINT, LPARAM, LPARAM)
def _browse_callback(handle, umsg, lparam, lpdata):
if(umsg == _BFFM_INITIALIZED):
if(lpdata is not None):
windll.user32.SendMessageA(handle, _BFFM_SETSELECTIONA, 1, lpdata)
return 0
class _SHITEMID(Structure):
_fields_ = [
("cb", USHORT),
("abID", BYTE)]
class _ITEMIDLIST(Structure):
_fields_ = [
("mkid", POINTER(_SHITEMID))]
class _BROWSEINFO(Structure):
_fields_ = [
("hwndOwner", HWND),
("pidlRoot", UINT),
("pszDisplayName", LPCSTR),
("lpszTitle", LPCSTR),
("ulFlags", UINT),
("lpfn", _BFFCALLBACK),
("lParam", LPARAM),
("iImage", INT)]
def browse_folder(path, message):
display_name = create_string_buffer(MAX_PATH)
end_path = create_string_buffer(MAX_PATH)
pidl_root = _ITEMIDLIST()
bi = _BROWSEINFO()
bi.hwndOwner = 0
bi.pidlRoot = 0
bi.pszDisplayName = addressof(display_name)
bi.lpszTitle = message.encode("ascii", "ignore")
bi.ulFlags = _BIF_RETURNONLYFSDIRS | _BIF_NEWDIALOGSTYLE
bi.lpfn = _BFFCALLBACK(_browse_callback)
bi.lParam = cast(path.encode("ascii", "ignore"), POINTER(LPARAM)).contents
bi.iImage = 0
pidl = windll.shell32.SHBrowseForFolder(addressof(bi))
print(display_name.value)
windll.shell32.SHGetPathFromIDList(pidl, addressof(end_path))
print(repr(end_path.value))

I switched to unicode and the wide character type as suggested by the comments.
The problem was casting it to an LPARAM and then dereferencing, but the comments led me to the method from_buffer on LPARAM.
I set lParam as follows:
bi.lParam = LPARAM.from_buffer(c_wchar_p(path))

Related

Ctypes - How to parser buffer content?

I have a code use SetupDiGetDeviceRegistryPropertyW to enumerate USB vendor id and product id , I read from buffer as <ctypes.LP_c_wchar object at 0x000001A3361F4C40>,how can i parse ?
Buffer
result = ct.cast(PropertyBuffer,ct.POINTER(w.WCHAR))
code
import ctypes as ct
from ctypes import wintypes as w
import uuid
SetupAPI = ct.WinDLL('SetupAPI')
ULONG_PTR = w.WPARAM
class HDEVINFO(w.HANDLE):
pass
class GUID(ct.Structure):
_fields_ = (('Data1', ct.c_ulong),
('Data2', ct.c_ushort),
('Data3', ct.c_ushort),
('Data4', ct.c_ubyte * 8))
def __repr__(self):
return f"GUID('{self}')"
def __str__(self):
return (f'{{{self.Data1:08x}-{self.Data2:04x}-{self.Data3:04x}-'
f'{bytes(self.Data4[:2]).hex()}-{bytes(self.Data4[2:]).hex()}}}')
def __init__(self,guid=None):
if guid is not None:
data = uuid.UUID(guid)
self.Data1 = data.time_low
self.Data2 = data.time_mid
self.Data3 = data.time_hi_version
self.Data4[0] = data.clock_seq_hi_variant
self.Data4[1] = data.clock_seq_low
self.Data4[2:] = data.node.to_bytes(6,'big')
PGUID = ct.POINTER(GUID)
GUID_DEVINTERFACE_USB_DEVICE = GUID('{A5DCBF10-6530-11D2-901F-00C04FB951ED}')
class SP_DEVINFO_DATA(ct.Structure):
_fields_ = (('cbSize', w.DWORD),
('ClassGuid', GUID),
('DevInst', w.DWORD),
('Reserved', ULONG_PTR))
def __repr__(self):
return f'SP_DEVINFO_DATA(ClassGuid={self.ClassGuid}, DevInst={self.DevInst})'
def __init__(self):
self.cbSize = ct.sizeof(SP_DEVINFO_DATA)
PSP_DEVINFO_DATA = ct.POINTER(SP_DEVINFO_DATA)
SetupAPI.SetupDiGetClassDevsW.argtypes = PGUID, w.PWCHAR, w.HWND, w.DWORD
SetupAPI.SetupDiGetClassDevsW.restype = HDEVINFO
SetupAPI.SetupDiEnumDeviceInfo.argtypes = HDEVINFO, w.DWORD, PSP_DEVINFO_DATA
SetupAPI.SetupDiEnumDeviceInfo.restype = w.BOOL
SetupAPI.SetupDiGetDeviceRegistryPropertyA.argtypes = HDEVINFO, PSP_DEVINFO_DATA,
w.DWORD, w.PDWORD, w.PBYTE, w.DWORD, w.PDWORD
SetupAPI.SetupDiGetDeviceRegistryPropertyA.restype = w.BOOL
SetupAPI.SetupDiDestroyDeviceInfoList.argtypes = HDEVINFO,
SetupAPI.SetupDiDestroyDeviceInfoList.restype = w.BOOL
DIGCF_DEFAULT = 0x00000001
DIGCF_PRESENT = 0x00000002
DIGCF_ALLCLASSES = 0x00000004
DIGCF_PROFILE = 0x00000008
DIGCF_DEVICEINTERFACE = 0x00000010
ClassGuid = GUID_DEVINTERFACE_USB_DEVICE
Enumerator = None
hwndParent = None
Flags = DIGCF_DEVICEINTERFACE | DIGCF_PRESENT
devinfo = SP_DEVINFO_DATA()
hDevInfo = SetupAPI.SetupDiGetClassDevsW(ClassGuid, Enumerator, hwndParent, Flags)
DeviceInfoSet = hDevInfo
DeviceInfoData = ct.byref(devinfo)
SPDRP_HARDWAREID = 0x00000001
PropertyRegDataType = None
PropertyBufferSize = 0
RequiredSize = w.DWORD()
try:
MemberIndex = 0
while SetupAPI.SetupDiEnumDeviceInfo(hDevInfo, MemberIndex, ct.byref(devinfo)):
print(devinfo)
SetupAPI.SetupDiGetDeviceRegistryPropertyW(
hDevInfo,
ct.byref(devinfo),
SPDRP_HARDWAREID,
PropertyRegDataType,
None,
PropertyBufferSize ,
ct.byref(RequiredSize))
PropertyBuffer = (w.BYTE * RequiredSize.value)()
if not SetupAPI.SetupDiGetDeviceRegistryPropertyW(
hDevInfo,
ct.byref(devinfo),
SPDRP_HARDWAREID,
PropertyRegDataType,
PropertyBuffer,
ct.sizeof(PropertyBuffer),
None):
break
result = ct.cast(PropertyBuffer,ct.POINTER(w.WCHAR))
print(result)
MemberIndex += 1
finally:
SetupAPI.SetupDiDestroyDeviceInfoList(hDevInfo)
Make sure you are initializing and calling the "W" version of the SetupDiGetDeviceRegistryProperty API:
SetupAPI.SetupDiGetDeviceRegistryPropertyW.argtypes = HDEVINFO, PSP_DEVINFO_DATA, w.DWORD, w.PDWORD, w.PBYTE, w.DWORD, w.PDWORD
SetupAPI.SetupDiGetDeviceRegistryPropertyW.restype = w.BOOL
The registry value being read is a MULTI_SZ, which is multiple zero-terminated strings, the last of which is double-terminated. The following function casts the return buffer to a C wchar_t*, but then uses string slicing to extracts "length" characters starting at that pointer address. The length is determined by dividing the returned buffer size by the size of a WCHAR. Then the trailing nulls are stripped from the data and the individual strings are split by the other nulls:
def get_multi_sz(buffer, length):
result = ct.cast(buffer, ct.POINTER(w.WCHAR))
strings = result[:RequiredSize.value // ct.sizeof(w.WCHAR)]
return strings.rstrip('\x00').split('\x00')
Finally, in your SetupDiEnumDeviceInfo while loop, print the list of strings returned by each device:
MemberIndex = 0
while SetupAPI.SetupDiEnumDeviceInfo(hDevInfo, MemberIndex, ct.byref(devinfo)):
print(devinfo)
SetupAPI.SetupDiGetDeviceRegistryPropertyW(
hDevInfo, ct.byref(devinfo), SPDRP_HARDWAREID, PropertyRegDataType,
None, PropertyBufferSize, ct.byref(RequiredSize))
PropertyBuffer = (w.BYTE * RequiredSize.value)()
if not SetupAPI.SetupDiGetDeviceRegistryPropertyW(
hDevInfo, ct.byref(devinfo), SPDRP_HARDWAREID, PropertyRegDataType,
PropertyBuffer, ct.sizeof(PropertyBuffer), None):
break
print(get_multi_sz(PropertyBuffer, RequiredSize.value))
MemberIndex += 1
Output with these changes (on my system, anyway):
SP_DEVINFO_DATA(ClassGuid={36fc9e60-c465-11cf-8056-444553540000}, DevInst=1)
['USB\\VID_046D&PID_C52B&REV_1201', 'USB\\VID_046D&PID_C52B']
SP_DEVINFO_DATA(ClassGuid={745a17a0-74d3-11d0-b6fe-00a0c90f57da}, DevInst=2)
['USB\\VID_046D&PID_C01B&REV_1800', 'USB\\VID_046D&PID_C01B']
SP_DEVINFO_DATA(ClassGuid={36fc9e60-c465-11cf-8056-444553540000}, DevInst=3)
['USB\\VID_03F0&PID_0122&REV_0100', 'USB\\VID_03F0&PID_0122']
SP_DEVINFO_DATA(ClassGuid={36fc9e60-c465-11cf-8056-444553540000}, DevInst=4)
['USB\\VID_046D&PID_0A87&REV_0112', 'USB\\VID_046D&PID_0A87']
Using a tool like UsbTreeView, you can verify the Hardware ID strings match. Here's an excerpt from that tool that matches the 3rd device's hardware IDs above:
======================== USB Device ========================
+++++++++++++++++ Device Information ++++++++++++++++++
Device Description : USB Composite Device
Device Path : \\?\USB#VID_03F0&PID_0122#5&35eda8e7&0&1#{a5dcbf10-6530-11d2-901f-00c04fb951ed} (GUID_DEVINTERFACE_USB_DEVICE)
Kernel Name : \Device\USBPDO-10
Device ID : USB\VID_03F0&PID_0122\5&35EDA8E7&0&1
Hardware IDs : USB\VID_03F0&PID_0122&REV_0100 USB\VID_03F0&PID_0122
Listing:
[Python.Docs]: ctypes - A foreign function library for Python
[MS.Docs]: SetupDiGetDeviceRegistryPropertyW function (setupapi.h) for info on how to parse the results. For example, according to [MS.Docs]: Registry Value Types (emphasis is mine):
REG_MULTI_SZ - A sequence of null-terminated strings, terminated by an empty string (\0). The following is an example: String1\0String2\0String3\0LastString\0\0 The first \0 terminates the first string, the second to the last \0 terminates the last string, and the final \0 terminates the sequence. Note that the final terminator must be factored into the length of the string.
Your code had several flaws (out of which matter most):
Continuation on a separate line of SetupAPI.SetupDiGetDeviceRegistryPropertyA.argtypes (without a \) - your program only works because the following bullet is masking this
Definig them for SetupDiGetDeviceRegistryPropertyA but using SetupDiGetDeviceRegistryPropertyW - which yields Undefined Behavior. Check [SO]: C function called from Python via ctypes returns incorrect value (#CristiFati's answer) for more details
Converting the array to a pointer doesn't make any sense, as it loses size information
I modified your script to a working version:
Extended parse_data to accommodate new data types (REG_DWORD, REG_SZ, REG_MULTI_SZ) - as originally only REG_MULTI_SZ data (corresponding to SPDRP_HARDWAREID property) was mentioned / required
Improved error handling
Extended functionality
Other minor things
code00.py:
#!/usr/bin/env python
import ctypes as ct
import sys
import uuid
import winreg as wr
from ctypes import wintypes as wt
ULONG_PTR = wt.WPARAM
HDEVINFO = wt.HANDLE
class GUID(ct.Structure):
_fields_ = (
("Data1", ct.c_ulong),
("Data2", ct.c_ushort),
("Data3", ct.c_ushort),
("Data4", ct.c_ubyte * 8),
)
def __repr__(self):
return f"GUID('{self}')"
def __str__(self):
return (f"{{{self.Data1:08x}-{self.Data2:04x}-{self.Data3:04x}-"
f"{bytes(self.Data4[:2]).hex()}-{bytes(self.Data4[2:]).hex()}}}")
def __init__(self,guid=None):
if guid is not None:
data = uuid.UUID(guid)
self.Data1 = data.time_low
self.Data2 = data.time_mid
self.Data3 = data.time_hi_version
self.Data4[0] = data.clock_seq_hi_variant
self.Data4[1] = data.clock_seq_low
self.Data4[2:] = data.node.to_bytes(6, "big")
PGUID = ct.POINTER(GUID)
class SP_DEVINFO_DATA(ct.Structure):
_fields_ = (
("cbSize", wt.DWORD),
("ClassGuid", GUID),
("DevInst", wt.DWORD),
("Reserved", ULONG_PTR),
)
def __repr__(self):
return f"SP_DEVINFO_DATA(ClassGuid={self.ClassGuid}, DevInst={self.DevInst})"
def __init__(self):
self.cbSize = ct.sizeof(self.__class__)
PSP_DEVINFO_DATA = ct.POINTER(SP_DEVINFO_DATA)
GUID_DEVINTERFACE_USB_DEVICE = GUID("{A5DCBF10-6530-11D2-901F-00C04FB951ED}")
kernel32 = ct.WinDLL("Kernel32")
GetLastError = kernel32.GetLastError
GetLastError.argtypes = ()
GetLastError.restype = wt.DWORD
setupapi = ct.WinDLL("Setupapi")
#is_wide = True # Determine whether using WIDE or ANSI functions
SetupDiGetClassDevs = setupapi.SetupDiGetClassDevsW #if is_wide else setupapi.SetupDiGetClassDevsA
SetupDiGetClassDevs.argtypes = (PGUID, wt.PWCHAR, wt.HWND, wt.DWORD)
SetupDiGetClassDevs.restype = HDEVINFO
SetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo
SetupDiEnumDeviceInfo.argtypes = (HDEVINFO, wt.DWORD, PSP_DEVINFO_DATA)
SetupDiEnumDeviceInfo.restype = wt.BOOL
SetupDiGetDeviceRegistryProperty = setupapi.SetupDiGetDeviceRegistryPropertyW #if is_wide else setupapi.SetupDiGetDeviceRegistryPropertyA
SetupDiGetDeviceRegistryProperty.argtypes = (HDEVINFO, PSP_DEVINFO_DATA, wt.DWORD, wt.PDWORD, wt.PBYTE, wt.DWORD, wt.PDWORD)
SetupDiGetDeviceRegistryProperty.restype = wt.BOOL
SetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList
SetupDiDestroyDeviceInfoList.argtypes = (HDEVINFO,)
SetupDiDestroyDeviceInfoList.restype = wt.BOOL
DIGCF_DEFAULT = 0x00000001
DIGCF_PRESENT = 0x00000002
DIGCF_ALLCLASSES = 0x00000004
DIGCF_PROFILE = 0x00000008
DIGCF_DEVICEINTERFACE = 0x00000010
def parse_data(arr, reg_data_type):
if reg_data_type is wr.REG_DWORD:
return wt.DWORD.from_buffer(arr).value
elif reg_data_type in (wr.REG_SZ, wr.REG_MULTI_SZ):
WArrType = wt.WCHAR * (arr._length_ // ct.sizeof(wt.WCHAR)) # Convert from char array to wchar_t array (halving size)
warr = WArrType.from_buffer(arr) # #TODO - cfati: You should probably use MultiByteToWideChar or mbstowcs here.
ret = str(warr[:len(warr)]).rstrip("\x00")
if reg_data_type is wr.REG_MULTI_SZ:
return ret.split("\x00")
elif reg_data_type is wr.REG_SZ:
return ret
else: # More types could be handled here
return arr
def main(*argv):
ClassGuid = GUID_DEVINTERFACE_USB_DEVICE
Enumerator = None
hwndParent = None
Flags = DIGCF_DEVICEINTERFACE | DIGCF_PRESENT
dev_info = SP_DEVINFO_DATA()
hDevInfo = SetupDiGetClassDevs(ClassGuid, Enumerator, hwndParent, Flags)
DeviceInfoSet = hDevInfo
property_reg_data_type = wt.DWORD(0)
required_size = wt.DWORD(0)
SPDRP_HARDWAREID = 0x00000001
SPDRP_CLASS = 0x00000007
SPDRP_FRIENDLYNAME = 0x0000000C
SPDRP_CAPABILITIES = 0x0000000F
SPDRP_BUSNUMBER = 0x00000015
SPDRP_DEVTYPE = 0x00000019
SPDRP_EXCLUSIVE = 0x0000001A
SPDRP_CHARACTERISTICS = 0x0000001B
SPDRP_ADDRESS = 0x0000001C
SPDRP_INSTALL_STATE = 0x00000022
props = (SPDRP_HARDWAREID, SPDRP_CLASS, SPDRP_FRIENDLYNAME, SPDRP_CAPABILITIES)
ERROR_INVALID_DATA = 0x0D
ERROR_INSUFFICIENT_BUFFER = 0x7A
try:
MemberIndex = 0
while SetupDiEnumDeviceInfo(hDevInfo, MemberIndex, ct.byref(dev_info)):
print(dev_info)
keep_running = True
for prop in props:
print(f" Prop: {prop}")
if not SetupDiGetDeviceRegistryProperty(
hDevInfo, ct.byref(dev_info), prop,
None, None, 0, ct.byref(required_size)):
gle = GetLastError()
if gle == ERROR_INVALID_DATA:
print(" Unsupported")
continue
elif gle != ERROR_INSUFFICIENT_BUFFER:
print(" Fail0:", gle)
keep_running = False
break
#print(" kkt", prop, required_size.value)
PropertyBuffer = wt.BYTE * required_size.value
property_buffer = PropertyBuffer()
if not SetupDiGetDeviceRegistryProperty(
hDevInfo, ct.byref(dev_info), prop,
ct.byref(property_reg_data_type),
property_buffer, ct.sizeof(PropertyBuffer), None):
gle = GetLastError()
print(" Fail1:", gle)
if gle != ERROR_INVALID_DATA:
keep_running = False
break
print(f" Data type: {property_reg_data_type.value} \
\n Buf: {property_buffer} \
\n Data: {parse_data(property_buffer, property_reg_data_type.value)}")
if not keep_running:
break
MemberIndex += 1
finally:
SetupDiDestroyDeviceInfoList(hDevInfo)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
Output:
[cfati#CFATI-5510-0:e:\Work\Dev\StackOverflow\q072847468]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ./code00.py
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
SP_DEVINFO_DATA(ClassGuid={4d36e972-e325-11ce-bfc1-08002be10318}, DevInst=1)
Prop: 1
Data type: 7
Buf: <__main__.c_byte_Array_108 object at 0x000002287E6F4F40>
Data: ['USB\\VID_0BDA&PID_8153&REV_3100', 'USB\\VID_0BDA&PID_8153']
Prop: 7
Data type: 1
Buf: <__main__.c_byte_Array_8 object at 0x000002287ECF60C0>
Data: Net
Prop: 12
Data type: 1
Buf: <__main__.c_byte_Array_74 object at 0x000002287E6F4F40>
Data: Realtek USB GbE Family Controller #2
Prop: 15
Data type: 4
Buf: <__main__.c_byte_Array_4 object at 0x000002287ECF6040>
Data: 148
SP_DEVINFO_DATA(ClassGuid={745a17a0-74d3-11d0-b6fe-00a0c90f57da}, DevInst=2)
Prop: 1
Data type: 7
Buf: <__main__.c_byte_Array_108 object at 0x000002287E6F4F40>
Data: ['USB\\VID_045E&PID_00CB&REV_0100', 'USB\\VID_045E&PID_00CB']
Prop: 7
Data type: 1
Buf: <__main__.c_byte_Array_18 object at 0x000002287ECF8040>
Data: HIDClass
Prop: 12
Unsupported
Prop: 15
Data type: 4
Buf: <__main__.c_byte_Array_4 object at 0x000002287E6F4F40>
Data: 132
SP_DEVINFO_DATA(ClassGuid={36fc9e60-c465-11cf-8056-444553540000}, DevInst=3)
Prop: 1
Data type: 7
Buf: <__main__.c_byte_Array_108 object at 0x000002287ECF80C0>
Data: ['USB\\VID_045E&PID_07F8&REV_0300', 'USB\\VID_045E&PID_07F8']
Prop: 7
Data type: 1
Buf: <__main__.c_byte_Array_8 object at 0x000002287E6F4F40>
Data: USB
Prop: 12
Unsupported
Prop: 15
Data type: 4
Buf: <__main__.c_byte_Array_4 object at 0x000002287ECF8040>
Data: 132
SP_DEVINFO_DATA(ClassGuid={e0cbf06c-cd8b-4647-bb8a-263b43f0f974}, DevInst=4)
Prop: 1
Data type: 7
Buf: <__main__.c_byte_Array_108 object at 0x000002287E6F4F40>
Data: ['USB\\VID_8087&PID_0A2B&REV_0001', 'USB\\VID_8087&PID_0A2B']
Prop: 7
Data type: 1
Buf: <__main__.c_byte_Array_20 object at 0x000002287ECF80C0>
Data: Bluetooth
Prop: 12
Unsupported
Prop: 15
Data type: 4
Buf: <__main__.c_byte_Array_4 object at 0x000002287E6F4F40>
Data: 128
SP_DEVINFO_DATA(ClassGuid={36fc9e60-c465-11cf-8056-444553540000}, DevInst=5)
Prop: 1
Data type: 7
Buf: <__main__.c_byte_Array_108 object at 0x000002287ECF8040>
Data: ['USB\\VID_0C45&PID_6713&REV_5605', 'USB\\VID_0C45&PID_6713']
Prop: 7
Data type: 1
Buf: <__main__.c_byte_Array_8 object at 0x000002287E6F4F40>
Data: USB
Prop: 12
Unsupported
Prop: 15
Data type: 4
Buf: <__main__.c_byte_Array_4 object at 0x000002287ECF80C0>
Data: 128
Done.

Attribute Error: module 'uctypes' has no attribute 'INT32'

When I try to run rcReceiver_IBUS.py, I am getting this error:
module 'uctypes' has no attribute 'INT32'
timer.py line 17
Your program tries to access attribute INT32 of an object of type 'uctypes', but this type doesn't have such attribute.
.
rcReceiver_IBUS.py
from machine import UART
import time
buffer=bytearray(31)
uart = UART(1, 115200) # uart1 tx-pin 4, rx-pin 5
while True:
c=uart.read(1)
if c[0] == 0x20:
uart.readinto(buffer)
checksum = 0xffff - 0x20
for i in range(29): checksum -= buffer[i]
if checksum == (buffer[30] << 8) | buffer[29]:
# skip buffer[0] = 0x40
ch1 = buffer[2]*255+buffer[1]
ch2 = buffer[4]*255+buffer[3]
ch3 = buffer[6]*255+buffer[5]
ch4 = buffer[8]*255+buffer[7]
ch5 = buffer[10]*255+buffer[9]
ch6 = buffer[12]*255+buffer[11]
print('ch 1-',ch1,' 2-',ch2,' 3-',ch3,' 4-',ch4,' 5-',ch5,' 6-',ch6)
.
timer.py
import ffilib
import uctypes
import array
import uos
import os
import utime
from signal import *
libc = ffilib.libc()
librt = ffilib.open("librt")
CLOCK_REALTIME = 0
CLOCK_MONOTONIC = 1
SIGEV_SIGNAL = 0
sigval_t = {
"sival_int": uctypes.INT32 | 0,
"sival_ptr": (uctypes.PTR | 0, uctypes.UINT8),
}
sigevent_t = {
"sigev_value": (0, sigval_t),
"sigev_signo": uctypes.INT32 | 8,
"sigev_notify": uctypes.INT32 | 12,
}
timespec_t = {
"tv_sec": uctypes.INT32 | 0,
"tv_nsec": uctypes.INT64 | 8,
}
itimerspec_t = {
"it_interval": (0, timespec_t),
"it_value": (16, timespec_t),
}
__libc_current_sigrtmin = libc.func("i", "__libc_current_sigrtmin", "")
SIGRTMIN = __libc_current_sigrtmin()
timer_create_ = librt.func("i", "timer_create", "ipp")
timer_settime_ = librt.func("i", "timer_settime", "PiPp")
def new(sdesc):
buf = bytearray(uctypes.sizeof(sdesc))
s = uctypes.struct(uctypes.addressof(buf), sdesc, uctypes.NATIVE)
return s
def timer_create(sig_id):
sev = new(sigevent_t)
#print(sev)
sev.sigev_notify = SIGEV_SIGNAL
sev.sigev_signo = SIGRTMIN + sig_id
timerid = array.array('P', [0])
r = timer_create_(CLOCK_MONOTONIC, sev, timerid)
os.check_error(r)
#print("timerid", hex(timerid[0]))
return timerid[0]
def timer_settime(tid, hz):
period = 1000000000 // hz
new_val = new(itimerspec_t)
new_val.it_value.tv_nsec = period
new_val.it_interval.tv_nsec = period
#print("new_val:", bytes(new_val))
old_val = new(itimerspec_t)
#print(new_val, old_val)
r = timer_settime_(tid, 0, new_val, old_val)
os.check_error(r)
#print("old_val:", bytes(old_val))
#print("timer_settime", r)
class Timer:
def __init__(self, id, freq):
self.id = id
self.tid = timer_create(id)
self.freq = freq
def callback(self, cb):
self.cb = cb
timer_settime(self.tid, self.freq)
org_sig = signal(SIGRTMIN + self.id, self.handler)
#print("Sig %d: %s" % (SIGRTMIN + self.id, org_sig))
def handler(self, signum):
#print('Signal handler called with signal', signum)
self.cb(self)
But when I open uctypes.py, INT32 is in the file. It seems there is no problem in file. What am I missing?
.
uctypes.py
ARRAY = -1073741824
BFINT16 = -671088640
BFINT32 = -402653184
BFINT8 = -939524096
BFUINT16 = -805306368
BFUINT32 = -536870912
BFUINT8 = -1073741824
BF_LEN = 22
BF_POS = 17
BIG_ENDIAN = 1
FLOAT32 = -268435456
FLOAT64 = -134217728
INT16 = 402653184
INT32 = 671088640
INT64 = 939524096
INT8 = 134217728
LITTLE_ENDIAN = 0
NATIVE = 2
PTR = 536870912
UINT16 = 268435456
UINT32 = 536870912
UINT64 = 805306368
UINT8 = 0
VOID = 0
def addressof():
pass
def bytearray_at():
pass
def bytes_at():
pass
def sizeof():
pass
class struct:
""

WinUSB.DLL and Python: Specifically WinUsb_Initialize

I've been following the WinUsb MSDN HowTo here and so far it's worked pretty well.
I've made it to the point in the guide where I have to call the WinUsb_Initialize() function from the WinUsb DLL. And that's where I'm stuck. My code so far is this, and you will doubtlessly ascertain that I've ripped a great deal of it screaming from the WinAPI.py module of PyWinUSB. Insert gratuitous thanks and giving credit to the creator of PyWinUSB here.
import ctypes
import platform
from ctypes import byref, POINTER, Structure, sizeof, c_ulong
from ctypes.wintypes import DWORD, WORD, BYTE, HANDLE, LPCWSTR, ULONG, WCHAR, \
BOOL
TCHAR = WCHAR
winUSB = ctypes.windll.winusb
winHID = ctypes.windll.hid
kernel32 = ctypes.windll.kernel32
setupAPI = ctypes.windll.setupapi
GENERIC_READ = (-2147483648)
GENERIC_WRITE = (1073741824)
FILE_SHARE_READ = 1
FILE_SHARE_WRITE = 2
OPEN_EXISTING = 3
FILE_FLAG_OVERLAPPED = 1073741824
if platform.architecture()[0].startswith('64'):
WIN_PACK = 8
else:
WIN_PACK = 1
class GUID(ctypes.Structure):
"""GUID Windows OS Structure"""
_pack_ = 1
_fields_ = [("data1", DWORD),
("data2", WORD),
("data3", WORD),
("data4", BYTE * 8)]
def __init__(self, data1 = None, data2 = None, data3 = None, data4 = None):
if data1 is not None:
self.data1 = data1
if data2 is not None:
self.data2 = data2
if data3 is not None:
self.data3 = data3
if data4 is not None:
self.data4 = data4
class SP_DEVICE_INTERFACE_DATA(Structure):
"""
typedef struct _SP_DEVICE_INTERFACE_DATA {
DWORD cbSize;
GUID InterfaceClassGuid;
DWORD Flags;
ULONG_PTR Reserved;
} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA
"""
_pack_ = WIN_PACK
_fields_ = [("cb_size", DWORD),
("interface_class_guid", GUID),
("flags", DWORD),
("reserved", POINTER(ULONG))]
def __init__(self):
self.cb_size = sizeof(SP_DEVICE_INTERFACE_DATA)
class SP_DEVICE_INTERFACE_DETAIL_DATA(Structure):
"""
typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
DWORD cbSize;
TCHAR DevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;
"""
_pack_ = WIN_PACK
_fields_ = [("cb_size", DWORD),
("device_path", TCHAR * 1)] #device_path[1]
def __init__(self):
self.cb_size = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)
def get_string(self):
"""Retreive stored string"""
return ctypes.wstring_at(byref(self, sizeof(DWORD)))
class SP_DEVINFO_DATA(Structure):
"""
typedef struct _SP_DEVINFO_DATA {
DWORD cbSize;
GUID ClassGuid;
DWORD DevInst;
ULONG_PTR Reserved;
} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
"""
_pack_ = WIN_PACK
_fields_ = [("cb_size", DWORD),
("class_guid", GUID),
("dev_inst", DWORD),
("reserved", POINTER(ULONG))]
def __init__(self):
self.cb_size = sizeof(SP_DEVINFO_DATA)
class DIGCF:
"""
Flags controlling what is included in the device information set
built by SetupDiGetClassDevs
"""
DEFAULT = 0x00000001
PRESENT = 0x00000002
ALLCLASSES = 0x00000004
PROFILE = 0x00000008
DEVICEINTERFACE = 0x00000010
def GetHidGuid():
"Get system-defined GUID for HIDClass devices"
hid_guid = GUID()
winHID.HidD_GetHidGuid(byref(hid_guid))
return hid_guid
SetupDiGetClassDevs = setupAPI.SetupDiGetClassDevsW
SetupDiGetClassDevs.restype = HANDLE
SetupDiGetClassDevs.argtypes = [
# __in_opt const GUID *ClassGuid,
# __in_opt PCTSTR Enumerator,
# __in_opt HWND hwndParent,
# __in DWORD Flags,
POINTER(GUID),
LPCWSTR,
HANDLE,
DWORD]
SetupDiGetDeviceInterfaceDetail = setupAPI.SetupDiGetDeviceInterfaceDetailW
SetupDiGetDeviceInterfaceDetail.restype = BOOL
SetupDiGetDeviceInterfaceDetail.argtypes = [
# __in HDEVINFO DeviceInfoSet,
# __in PSP_DEVICE_INTERFACE_DATA DeviceIn,
# __out_opt PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,
# __in DWORD DeviceInterfaceDetailDataSize,
# __out_opt PDWORD RequiredSize
# __out_opt PSP_DEVINFO_DATA DeviceInfoData
HANDLE,
POINTER(SP_DEVICE_INTERFACE_DATA),
POINTER(SP_DEVICE_INTERFACE_DETAIL_DATA),
DWORD,
POINTER(DWORD),
POINTER(SP_DEVINFO_DATA)]
devGuid = GUID(0x2518E22E, 0x0F35, 0x11E2, (BYTE * 8)(0xB1, 0xD5, 0x6C, 0xF0,
0x49, 0x73, 0x78, 0x72))
classGuid = GetHidGuid()
#GUID(0x745A17A0, 0x74D3, 0x11D0, (BYTE * 8)(0xB6, 0xFE, 0x00, 0xA0,
# 0xC9, 0x0F, 0x57, 0xDA))
derp = SetupDiGetClassDevs(
byref(classGuid), None, None,
(DIGCF.PRESENT | DIGCF.DEVICEINTERFACE))
def stepDevices(herp, index = 0):
devInterfaceData = SP_DEVICE_INTERFACE_DATA()
if setupAPI.SetupDiEnumDeviceInterfaces(
herp, None, byref(classGuid), index, byref(devInterfaceData)):
yield devInterfaceData
del devInterfaceData
else:
print(kernel32.GetLastError())
def enumDevices(herp):
index = 0
devInterfaceData = SP_DEVICE_INTERFACE_DATA()
while setupAPI.SetupDiEnumDeviceInterfaces(
herp, None, byref(classGuid), index, byref(devInterfaceData)):
print(kernel32.GetLastError())
yield devInterfaceData
index += 1
del devInterfaceData
def getDetail(herp, devData, devInfo = None):
reqSize = c_ulong(0)
devDetail = SP_DEVICE_INTERFACE_DETAIL_DATA()
SetupDiGetDeviceInterfaceDetail(
herp, byref(devData), None, 0, byref(reqSize), None)
ctypes.resize(devDetail, reqSize.value)
SetupDiGetDeviceInterfaceDetail(
herp, byref(devData), byref(devDetail),
reqSize, None, byref(devInfo))
return devDetail.get_string()
dev = stepDevices(derp).next()
devInfo = SP_DEVINFO_DATA()
devString = getDetail(derp, dev, devInfo)
winUSBHandle = kernel32.CreateFileW(
devString, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, None)
#winUSB.WinUsb_Initialize(winUSBHandle, <what goes here?>)
I've tried creating a simple handle and passing that byref(handle) as the second parameter to the function, but the handle value stays as None.
I don't know how much has been done with Python and WinUSB.DLL but if anyone can point me in the correct direction I'd be sincerely grateful.
Thanks in advance.
The documentation says it is a PWINUSB_INTERFACE_HANDLE, which is a PVOID, which is a c_void_p in ctypes, so this should work:
h = ctypes.c_void_p()
winUSB.WinUsb_Initialize(winUSBHandle, ctypes.byref(h))
Does the winUSBHandle look valid (not 0 or -1 or 0xFFFFFFFF)?
Edit
If it is failing, make sure to use the ctypes copy of GetLastError or it may be incorrect. Make the library references with:
winUSB = ctypes.WinDLL('winusb',use_last_error=True)
and use:
ctypes.get_last_error()

python ctypes Win32 way window title gets truncted?

I been trying to create Win32 Application by using python (2.7) and ctypes module. Window is created and shown but title of window gets truncated. I got 'M' instead of 'My test window'. What I am doing wrong?
Thanks in advance
P.S. Here follows the code and screenshot:
# -*- coding: utf-8 -*-
from sys import platform, exit
from ctypes import *
from ctypes.wintypes import DWORD, HWND, HANDLE, LPCWSTR, WPARAM, LPARAM, RECT, POINT, MSG
WNDPROCTYPE = WINFUNCTYPE(c_int, HWND, c_uint, WPARAM, LPARAM)
WS_EX_APPWINDOW = 0x40000
WS_OVERLAPPEDWINDOW = 0xcf0000
WS_CAPTION = 0xc00000
SW_SHOWNORMAL = 1
SW_SHOW = 5
CS_HREDRAW = 2
CS_VREDRAW = 1
CW_USEDEFAULT = 0x80000000
WM_DESTROY = 2
WHITE_BRUSH = 0
class WNDCLASSEX(Structure):
_fields_ = [("cbSize", c_uint),
("style", c_uint),
("lpfnWndProc", WNDPROCTYPE),
("cbClsExtra", c_int),
("cbWndExtra", c_int),
("hInstance", HANDLE),
("hIcon", HANDLE),
("hCursor", HANDLE),
("hBrush", HANDLE),
("lpszMenuName", LPCWSTR),
("lpszClassName", LPCWSTR),
("hIconSm", HANDLE)]
def PyWndProcedure(hWnd, Msg, wParam, lParam):
if Msg == WM_DESTROY:
windll.user32.PostQuitMessage(0)
else:
return windll.user32.DefWindowProcA(hWnd, Msg, wParam, lParam)
return 0
WndProc = WNDPROCTYPE(PyWndProcedure)
hInst = windll.kernel32.GetModuleHandleW(0)
print(hInst)
wclassName = u'My Python Win32 Class'
wndClass = WNDCLASSEX()
wndClass.cbSize = sizeof(WNDCLASSEX)
wndClass.style = CS_HREDRAW | CS_VREDRAW
wndClass.lpfnWndProc = WndProc
wndClass.cbClsExtra = 0
wndClass.cbWndExtra = 0
wndClass.hInstance = hInst
wndClass.hIcon = 0
wndClass.hCursor = 0
wndClass.hBrush = windll.gdi32.GetStockObject(WHITE_BRUSH)
wndClass.lpszMenuName = 0
wndClass.lpszClassName = wclassName
wndClass.hIconSm = 0
print(wndClass)
regRes = windll.user32.RegisterClassExW(byref(wndClass))
print(regRes)
wname = u'My test window'
hWnd = windll.user32.CreateWindowExW(
0,
wclassName,
wname,
WS_OVERLAPPEDWINDOW | WS_CAPTION,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
300,
0,
0,
hInst,
0)
print('hWnd', hWnd)
if not hWnd:
print('Failed to create window')
exit(0)
print('ShowWindow', windll.user32.ShowWindow(hWnd, SW_SHOW))
print('UpdateWindow', windll.user32.UpdateWindow(hWnd))
msg = MSG()
lpmsg = pointer(msg)
print('Entering message loop')
while windll.user32.GetMessageA(lpmsg, 0, 0, 0) != 0:
windll.user32.TranslateMessage(lpmsg)
windll.user32.DispatchMessageA(lpmsg)
print('done.')
It is because you are creating a Unicode window with CreateWindowExW but then calling the ANSI DefWindowProcA. You are passing Unicode strings which typically have zero for every other byte since your text is in the ASCII range which explains what you observe.
The solution? Call DefWindowProcW instead.
Actually, a better solution would be to use win32gui instead which wraps this up a bit more for you.
If you provide a regular string rather than an unicode string, the text is displayed properly.
wname = 'My test window'
It looks strange to me because you are using the Unicode API (CreateWindowExW). Maybe the root cause is somewhere else.
I hope it helps

How can I retrieve the signal strength of nearby wireless LAN networks on Windows using Python?

How can I retrieve the signal strength of nearby wireless LAN networks on Windows using Python?
I would like to either show or graph the values.
If you are on Windows, you probably want to use the WLAN API, which provides the 'WlanGetAvailableNetworkList()' function (see the API docs for usage). I am not aware of any python wrappers for WLANAPI.DLL so you may have to wrap it yourself using ctypes. I have a preliminary script that does this (works-for-me), but it may be crufty. You'll want to read the documentation to understand the meaning of all the fields:
from ctypes import *
from ctypes.wintypes import *
from sys import exit
def customresize(array, new_size):
return (array._type_*new_size).from_address(addressof(array))
wlanapi = windll.LoadLibrary('wlanapi.dll')
ERROR_SUCCESS = 0
class GUID(Structure):
_fields_ = [
('Data1', c_ulong),
('Data2', c_ushort),
('Data3', c_ushort),
('Data4', c_ubyte*8),
]
WLAN_INTERFACE_STATE = c_uint
(wlan_interface_state_not_ready,
wlan_interface_state_connected,
wlan_interface_state_ad_hoc_network_formed,
wlan_interface_state_disconnecting,
wlan_interface_state_disconnected,
wlan_interface_state_associating,
wlan_interface_state_discovering,
wlan_interface_state_authenticating) = map(WLAN_INTERFACE_STATE, range(0, 8))
class WLAN_INTERFACE_INFO(Structure):
_fields_ = [
("InterfaceGuid", GUID),
("strInterfaceDescription", c_wchar * 256),
("isState", WLAN_INTERFACE_STATE)
]
class WLAN_INTERFACE_INFO_LIST(Structure):
_fields_ = [
("NumberOfItems", DWORD),
("Index", DWORD),
("InterfaceInfo", WLAN_INTERFACE_INFO * 1)
]
WLAN_MAX_PHY_TYPE_NUMBER = 0x8
DOT11_SSID_MAX_LENGTH = 32
WLAN_REASON_CODE = DWORD
DOT11_BSS_TYPE = c_uint
(dot11_BSS_type_infrastructure,
dot11_BSS_type_independent,
dot11_BSS_type_any) = map(DOT11_BSS_TYPE, range(1, 4))
DOT11_PHY_TYPE = c_uint
dot11_phy_type_unknown = 0
dot11_phy_type_any = 0
dot11_phy_type_fhss = 1
dot11_phy_type_dsss = 2
dot11_phy_type_irbaseband = 3
dot11_phy_type_ofdm = 4
dot11_phy_type_hrdsss = 5
dot11_phy_type_erp = 6
dot11_phy_type_ht = 7
dot11_phy_type_IHV_start = 0x80000000
dot11_phy_type_IHV_end = 0xffffffff
DOT11_AUTH_ALGORITHM = c_uint
DOT11_AUTH_ALGO_80211_OPEN = 1
DOT11_AUTH_ALGO_80211_SHARED_KEY = 2
DOT11_AUTH_ALGO_WPA = 3
DOT11_AUTH_ALGO_WPA_PSK = 4
DOT11_AUTH_ALGO_WPA_NONE = 5
DOT11_AUTH_ALGO_RSNA = 6
DOT11_AUTH_ALGO_RSNA_PSK = 7
DOT11_AUTH_ALGO_IHV_START = 0x80000000
DOT11_AUTH_ALGO_IHV_END = 0xffffffff
DOT11_CIPHER_ALGORITHM = c_uint
DOT11_CIPHER_ALGO_NONE = 0x00
DOT11_CIPHER_ALGO_WEP40 = 0x01
DOT11_CIPHER_ALGO_TKIP = 0x02
DOT11_CIPHER_ALGO_CCMP = 0x04
DOT11_CIPHER_ALGO_WEP104 = 0x05
DOT11_CIPHER_ALGO_WPA_USE_GROUP = 0x100
DOT11_CIPHER_ALGO_RSN_USE_GROUP = 0x100
DOT11_CIPHER_ALGO_WEP = 0x101
DOT11_CIPHER_ALGO_IHV_START = 0x80000000
DOT11_CIPHER_ALGO_IHV_END = 0xffffffff
WLAN_AVAILABLE_NETWORK_CONNECTED = 1
WLAN_AVAILABLE_NETWORK_HAS_PROFILE = 2
WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES = 0x00000001
WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES = 0x00000002
class DOT11_SSID(Structure):
_fields_ = [
("SSIDLength", c_ulong),
("SSID", c_char * DOT11_SSID_MAX_LENGTH)
]
class WLAN_AVAILABLE_NETWORK(Structure):
_fields_ = [
("ProfileName", c_wchar * 256),
("dot11Ssid", DOT11_SSID),
("dot11BssType", DOT11_BSS_TYPE),
("NumberOfBssids", c_ulong),
("NetworkConnectable", c_bool),
("wlanNotConnectableReason", WLAN_REASON_CODE),
("NumberOfPhyTypes", c_ulong),
("dot11PhyTypes", DOT11_PHY_TYPE * WLAN_MAX_PHY_TYPE_NUMBER),
("MorePhyTypes", c_bool),
("wlanSignalQuality", c_ulong),
("SecurityEnabled", c_bool),
("dot11DefaultAuthAlgorithm", DOT11_AUTH_ALGORITHM),
("dot11DefaultCipherAlgorithm", DOT11_CIPHER_ALGORITHM),
("Flags", DWORD),
("Reserved", DWORD)
]
class WLAN_AVAILABLE_NETWORK_LIST(Structure):
_fields_ = [
("NumberOfItems", DWORD),
("Index", DWORD),
("Network", WLAN_AVAILABLE_NETWORK * 1)
]
WlanOpenHandle = wlanapi.WlanOpenHandle
WlanOpenHandle.argtypes = (DWORD, c_void_p, POINTER(DWORD), POINTER(HANDLE))
WlanOpenHandle.restype = DWORD
WlanEnumInterfaces = wlanapi.WlanEnumInterfaces
WlanEnumInterfaces.argtypes = (HANDLE, c_void_p,
POINTER(POINTER(WLAN_INTERFACE_INFO_LIST)))
WlanEnumInterfaces.restype = DWORD
WlanGetAvailableNetworkList = wlanapi.WlanGetAvailableNetworkList
WlanGetAvailableNetworkList.argtypes = (HANDLE, POINTER(GUID), DWORD, c_void_p,
POINTER(POINTER(WLAN_AVAILABLE_NETWORK_LIST)))
WlanGetAvailableNetworkList.restype = DWORD
WlanFreeMemory = wlanapi.WlanFreeMemory
WlanFreeMemory.argtypes = [c_void_p]
if __name__ == '__main__':
NegotiatedVersion = DWORD()
ClientHandle = HANDLE()
ret = WlanOpenHandle(1, None, byref(NegotiatedVersion), byref(ClientHandle))
if ret != ERROR_SUCCESS:
exit(FormatError(ret))
# find all wireless network interfaces
pInterfaceList = pointer(WLAN_INTERFACE_INFO_LIST())
ret = WlanEnumInterfaces(ClientHandle, None, byref(pInterfaceList))
if ret != ERROR_SUCCESS:
exit(FormatError(ret))
try:
ifaces = customresize(pInterfaceList.contents.InterfaceInfo,
pInterfaceList.contents.NumberOfItems)
# find each available network for each interface
for iface in ifaces:
print("Interface: {}".format(iface.strInterfaceDescription))
pAvailableNetworkList = pointer(WLAN_AVAILABLE_NETWORK_LIST())
ret = WlanGetAvailableNetworkList(ClientHandle,
byref(iface.InterfaceGuid),
0,
None,
byref(pAvailableNetworkList))
if ret != ERROR_SUCCESS:
exit(FormatError(ret))
try:
avail_net_list = pAvailableNetworkList.contents
networks = customresize(avail_net_list.Network,
avail_net_list.NumberOfItems)
for network in networks:
print("SSID: {}, quality: {:2d}%".format(
network.dot11Ssid.SSID[:network.dot11Ssid.SSIDLength].decode(),
network.wlanSignalQuality))
finally:
WlanFreeMemory(pAvailableNetworkList)
finally:
WlanFreeMemory(pInterfaceList)
On linux, you have a couple of choices:
The standard options is to parse the output of iwlist -scan. However, if you are currently connected to a wlan and not running as root, it only returns the currently connected wlan.
If you need more than this, the best way is to query the wireless manager daemon. On modern, linuxes, this is usually NetworkManager, although wicd is becoming more popular. Both of these managers can be queried using dbus. Unless you can control what the clients have on their systems, you might need to support both of these options, or at least one option and have a fallback for iwlist.
If you don't want to deal with Windows API you could use method shown here with a slight modification.
You can use this command:
netsh wlan show networks mode=Bssid
using this code
import subprocess
results = subprocess.check_output(["netsh", "wlan", "show", "network", "mode=Bssid"])
This will give you additiona "Signal" information as a percentage. This can be converted to RSSI using this method.
So.. I based myself on #fmarks code (which was a live-safer for me), and you should add the WlanScan function, or else the RSSI values will not refresh.
Here is my extended code!
All props to #fmarks!
__author__ = 'Pedro Gomes'
import time
from ctypes import *
from ctypes.wintypes import *
from sys import exit
def customresize(array, new_size):
return (array._type_*new_size).from_address(addressof(array))
wlanapi = windll.LoadLibrary('wlanapi.dll')
ERROR_SUCCESS = 0
class GUID(Structure):
_fields_ = [
('Data1', c_ulong),
('Data2', c_ushort),
('Data3', c_ushort),
('Data4', c_ubyte*8),
]
WLAN_INTERFACE_STATE = c_uint
(wlan_interface_state_not_ready,
wlan_interface_state_connected,
wlan_interface_state_ad_hoc_network_formed,
wlan_interface_state_disconnecting,
wlan_interface_state_disconnected,
wlan_interface_state_associating,
wlan_interface_state_discovering,
wlan_interface_state_authenticating) = map(WLAN_INTERFACE_STATE, xrange(0, 8))
class WLAN_INTERFACE_INFO(Structure):
_fields_ = [
("InterfaceGuid", GUID),
("strInterfaceDescription", c_wchar * 256),
("isState", WLAN_INTERFACE_STATE)
]
class WLAN_INTERFACE_INFO_LIST(Structure):
_fields_ = [
("NumberOfItems", DWORD),
("Index", DWORD),
("InterfaceInfo", WLAN_INTERFACE_INFO * 1)
]
WLAN_MAX_PHY_TYPE_NUMBER = 0x8
DOT11_SSID_MAX_LENGTH = 32
WLAN_REASON_CODE = DWORD
DOT11_BSS_TYPE = c_uint
(dot11_BSS_type_infrastructure,
dot11_BSS_type_independent,
dot11_BSS_type_any) = map(DOT11_BSS_TYPE, xrange(1, 4))
DOT11_PHY_TYPE = c_uint
dot11_phy_type_unknown = 0
dot11_phy_type_any = 0
dot11_phy_type_fhss = 1
dot11_phy_type_dsss = 2
dot11_phy_type_irbaseband = 3
dot11_phy_type_ofdm = 4
dot11_phy_type_hrdsss = 5
dot11_phy_type_erp = 6
dot11_phy_type_ht = 7
dot11_phy_type_IHV_start = 0x80000000
dot11_phy_type_IHV_end = 0xffffffff
DOT11_AUTH_ALGORITHM = c_uint
DOT11_AUTH_ALGO_80211_OPEN = 1
DOT11_AUTH_ALGO_80211_SHARED_KEY = 2
DOT11_AUTH_ALGO_WPA = 3
DOT11_AUTH_ALGO_WPA_PSK = 4
DOT11_AUTH_ALGO_WPA_NONE = 5
DOT11_AUTH_ALGO_RSNA = 6
DOT11_AUTH_ALGO_RSNA_PSK = 7
DOT11_AUTH_ALGO_IHV_START = 0x80000000
DOT11_AUTH_ALGO_IHV_END = 0xffffffff
DOT11_CIPHER_ALGORITHM = c_uint
DOT11_CIPHER_ALGO_NONE = 0x00
DOT11_CIPHER_ALGO_WEP40 = 0x01
DOT11_CIPHER_ALGO_TKIP = 0x02
DOT11_CIPHER_ALGO_CCMP = 0x04
DOT11_CIPHER_ALGO_WEP104 = 0x05
DOT11_CIPHER_ALGO_WPA_USE_GROUP = 0x100
DOT11_CIPHER_ALGO_RSN_USE_GROUP = 0x100
DOT11_CIPHER_ALGO_WEP = 0x101
DOT11_CIPHER_ALGO_IHV_START = 0x80000000
DOT11_CIPHER_ALGO_IHV_END = 0xffffffff
WLAN_AVAILABLE_NETWORK_CONNECTED = 1
WLAN_AVAILABLE_NETWORK_HAS_PROFILE = 2
WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES = 0x00000001
WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES = 0x00000002
class DOT11_SSID(Structure):
_fields_ = [
("SSIDLength", c_ulong),
("SSID", c_char * DOT11_SSID_MAX_LENGTH)
]
class WLAN_AVAILABLE_NETWORK(Structure):
_fields_ = [
("ProfileName", c_wchar * 256),
("dot11Ssid", DOT11_SSID),
("dot11BssType", DOT11_BSS_TYPE),
("NumberOfBssids", c_ulong),
("NetworkConnectable", c_bool),
("wlanNotConnectableReason", WLAN_REASON_CODE),
("NumberOfPhyTypes", c_ulong),
("dot11PhyTypes", DOT11_PHY_TYPE * WLAN_MAX_PHY_TYPE_NUMBER),
("MorePhyTypes", c_bool),
("wlanSignalQuality", c_ulong),
("SecurityEnabled", c_bool),
("dot11DefaultAuthAlgorithm", DOT11_AUTH_ALGORITHM),
("dot11DefaultCipherAlgorithm", DOT11_CIPHER_ALGORITHM),
("Flags", DWORD),
("Reserved", DWORD)
]
class WLAN_AVAILABLE_NETWORK_LIST(Structure):
_fields_ = [
("NumberOfItems", DWORD),
("Index", DWORD),
("Network", WLAN_AVAILABLE_NETWORK * 1)
]
DOT11_MAC_ADDRESS = c_ubyte * 6
DOT11_CIPHER_ALGORITHM = c_uint
DOT11_CIPHER_ALGO_NONE = 0x00
DOT11_CIPHER_ALGO_WEP40 = 0x01
DOT11_CIPHER_ALGO_TKIP = 0x02
DOT11_PHY_TYPE = c_uint
DOT11_PHY_TYPE_UNKNOWN = 0
DOT11_PHY_TYPE_ANY = 0
DOT11_PHY_TYPE_FHSS = 1
DOT11_PHY_TYPE_DSSS = 2
DOT11_PHY_TYPE_IRBASEBAND = 3
DOT11_PHY_TYPE_OFDM = 4
DOT11_PHY_TYPE_HRDSSS = 5
DOT11_PHY_TYPE_ERP = 6
DOT11_PHY_TYPE_HT = 7
DOT11_PHY_TYPE_IHV_START = 0X80000000
DOT11_PHY_TYPE_IHV_END = 0XFFFFFFFF
class WLAN_RATE_SET(Structure):
_fields_ = [
("uRateSetLength", c_ulong),
("usRateSet", c_ushort * 126)
]
class WLAN_BSS_ENTRY(Structure):
_fields_ = [
("dot11Ssid",DOT11_SSID),
("uPhyId",c_ulong),
("dot11Bssid", DOT11_MAC_ADDRESS),
("dot11BssType", DOT11_BSS_TYPE),
("dot11BssPhyType", DOT11_PHY_TYPE),
("lRssi", c_long),
("uLinkQuality", c_ulong),
("bInRegDomain", c_bool),
("usBeaconPeriod",c_ushort),
("ullTimestamp", c_ulonglong),
("ullHostTimestamp",c_ulonglong),
("usCapabilityInformation",c_ushort),
("ulChCenterFrequency", c_ulong),
("wlanRateSet",WLAN_RATE_SET),
("ulIeOffset", c_ulong),
("ulIeSize", c_ulong)]
class WLAN_BSS_LIST(Structure):
_fields_ = [
("TotalSize", DWORD),
("NumberOfItems", DWORD),
("NetworkBSS", WLAN_BSS_ENTRY * 1)
]
class WLAN_AVAILABLE_NETWORK_LIST_BSS(Structure):
_fields_ = [
("TotalSize", DWORD),
("NumberOfItems", DWORD),
("Network", WLAN_BSS_ENTRY * 1)
]
WlanOpenHandle = wlanapi.WlanOpenHandle
WlanOpenHandle.argtypes = (DWORD, c_void_p, POINTER(DWORD), POINTER(HANDLE))
WlanOpenHandle.restype = DWORD
WlanCloseHandle = wlanapi.WlanCloseHandle
WlanCloseHandle.argtypes = (HANDLE, c_void_p)
WlanCloseHandle.restype = DWORD
WlanEnumInterfaces = wlanapi.WlanEnumInterfaces
WlanEnumInterfaces.argtypes = (HANDLE, c_void_p,
POINTER(POINTER(WLAN_INTERFACE_INFO_LIST)))
WlanEnumInterfaces.restype = DWORD
WlanGetAvailableNetworkList = wlanapi.WlanGetAvailableNetworkList
WlanGetAvailableNetworkList.argtypes = (HANDLE, POINTER(GUID), DWORD, c_void_p,
POINTER(POINTER(WLAN_AVAILABLE_NETWORK_LIST)))
WlanGetAvailableNetworkList.restype = DWORD
WlanGetNetworkBssList = wlanapi.WlanGetNetworkBssList
WlanGetNetworkBssList.argtypes = (HANDLE, POINTER(GUID),POINTER(GUID),POINTER(GUID), c_bool, c_void_p,
POINTER(POINTER(WLAN_BSS_LIST)))
WlanGetNetworkBssList.restype = DWORD
WlanFreeMemory = wlanapi.WlanFreeMemory
WlanFreeMemory.argtypes = [c_void_p]
WlanScan = wlanapi.WlanScan
WlanScan.argtypes = (HANDLE, POINTER(GUID),c_void_p,c_void_p, c_void_p)
WlanScan.restype = DWORD
def get_interface():
NegotiatedVersion = DWORD()
ClientHandle = HANDLE()
ret = WlanOpenHandle(1, None, byref(NegotiatedVersion), byref(ClientHandle))
if ret != ERROR_SUCCESS:
exit(FormatError(ret))
# find all wireless network interfaces
pInterfaceList = pointer(WLAN_INTERFACE_INFO_LIST())
ret = WlanEnumInterfaces(ClientHandle, None, byref(pInterfaceList))
if ret != ERROR_SUCCESS:
exit(FormatError(ret))
try:
ifaces = customresize(pInterfaceList.contents.InterfaceInfo,
pInterfaceList.contents.NumberOfItems)
# find each available network for each interface
for iface in ifaces:
#print "Interface: %s" % (iface.strInterfaceDescription)
interface = iface.strInterfaceDescription
finally:
WlanFreeMemory(pInterfaceList)
return interface
class MAC_BSSID_POWER:
"""Classe para os valores retirados"""
def __init__(self, mac, bssid):
self.mac = str(mac)
self.bssid = str(bssid)
self.valores = []
def addPower(self,power):
self.valores.append(int(power))
def getBssid(self):
return self.bssid
def getPowers(self):
return self.valores
def getMac(self):
return self.mac
def get_BSSI():
BSSI_Values={}
NegotiatedVersion = DWORD()
ClientHandle = HANDLE()
ret = WlanOpenHandle(1, None, byref(NegotiatedVersion), byref(ClientHandle))
if ret != ERROR_SUCCESS:
exit(FormatError(ret))
# find all wireless network interfaces
pInterfaceList = pointer(WLAN_INTERFACE_INFO_LIST())
ret = WlanEnumInterfaces(ClientHandle, None, byref(pInterfaceList))
if ret != ERROR_SUCCESS:
exit(FormatError(ret))
try:
ifaces = customresize(pInterfaceList.contents.InterfaceInfo,
pInterfaceList.contents.NumberOfItems)
# find each available network for each interface
for iface in ifaces:
# print "Interface: %s" % (iface.strInterfaceDescription)
pAvailableNetworkList2 = pointer(WLAN_BSS_LIST())
ret2 = WlanGetNetworkBssList(ClientHandle,
byref(iface.InterfaceGuid),
None,
None,True,None,
byref(pAvailableNetworkList2))
if ret2 != ERROR_SUCCESS:
exit(FormatError(ret2))
try:
retScan = WlanScan(ClientHandle,byref(iface.InterfaceGuid),None,None,None)
if retScan != ERROR_SUCCESS:
exit(FormatError(retScan))
avail_net_list2 = pAvailableNetworkList2.contents
networks2 = customresize(avail_net_list2.NetworkBSS,
avail_net_list2.NumberOfItems)
for network in networks2:
SSID = str(network.dot11Ssid.SSID[:network.dot11Ssid.SSIDLength])
BSSID = ':'.join('%02x' % b for b in network.dot11Bssid).upper()
signal_strength = str(network.lRssi)
# print "SSID: " + SSID + " BSSID: "+ BSSID+ " SS: "+signal_strength
BSSI_Values[BSSID] = [SSID,signal_strength]
#print "Total "+str(len(networks2))
#print BSSI_Values
finally:
WlanFreeMemory(pAvailableNetworkList2)
WlanCloseHandle(ClientHandle,None)
finally:
WlanFreeMemory(pInterfaceList)
return BSSI_Values
def get_BSSI_times_and_total_seconds(times,seconds):
BSSI_to_return = {}
for i in range(0,seconds*times):
time_to_sleep = float(1.0/times)
time.sleep(time_to_sleep)
got_bssi_temp = get_BSSI()
for bssi in got_bssi_temp:
if not BSSI_to_return.get(bssi):
BSSI_to_return[bssi] = MAC_BSSID_POWER(bssi,got_bssi_temp[bssi][0])
BSSI_to_return[bssi].addPower( got_bssi_temp[bssi][1] )
#BSSI_to_return[bssi] = [got_bssi_temp[bssi][1]]
else:
BSSI_to_return[bssi].addPower( got_bssi_temp[bssi][1] )
#BSSI_to_return[bssi].append(got_bssi_temp[bssi][1])
print "Medicao "+str(i)+" de "+str(seconds*times)
print BSSI_to_return
return BSSI_to_return
if __name__ == '__main__':
#print get_interface()
import time
test = get_BSSI()
for i in range(0,10):
time.sleep(0.5)
oldTest = test
test = get_BSSI()
print "Teste: "+str(i)
if oldTest == test:
print "IGUAL"
else:
print "DIFERENTE"
print test
print "End"
#fmark I just wanted to say THANK YOU so much for this awesome post. At my work I have been trying to get RSSI from the connected AP in Windows, and you deserve many thanks for me finally getting it done. I'm currently listing all APs, but I'm working on modifying it. I wanted to offer a recommendation towards your code. I'm not very experienced with C or the Python CTypes module, but I think I might have found a possible bug. I'm really not sure what difference it makes, but I noticed:
You define enums like this:
DOT11_BSS_TYPE = c_uint
(dot11_BSS_type_infrastructure,
dot11_BSS_type_independent,
dot11_BSS_type_any) = map(DOT11_BSS_TYPE, xrange(1, 4))
But then other times you define something very similar like this:
DOT11_PHY_TYPE = c_uint
dot11_phy_type_unknown = 0
dot11_phy_type_any = 0
dot11_phy_type_fhss = 1
dot11_phy_type_dsss = 2
dot11_phy_type_irbaseband = 3
dot11_phy_type_ofdm = 4
dot11_phy_type_hrdsss = 5
dot11_phy_type_erp = 6
dot11_phy_type_ht = 7
dot11_phy_type_IHV_start = 0x80000000
dot11_phy_type_IHV_end = 0xffffffff
I think the second snippit should be modeled like the first, but I could be wrong. Here was my idea:
DOT11_PHY_TYPE = c_uint
(dot11_phy_type_unknown,
dot11_phy_type_any,
dot11_phy_type_fhss,
dot11_phy_type_dsss,
dot11_phy_type_irbaseband,
dot11_phy_type_ofdm,
dot11_phy_type_hrdsss,
dot11_phy_type_erp,
dot11_phy_type_ht,
dot11_phy_type_IHV_start,
dot11_phy_type_IHV_end) = map(DOT11_PHY_TYPE,
[0,0,1,2,3,4,
5,6,7,0x80000000,
0xffffffff])
This way those values would get correctly mapped to DOT11_PHY_TYPE. Perhaps I am completely wrong, but for future folks like myself, I just wanted whatever is stumbled on here to be correct :)
Thanks again, #fmark.

Categories