[英]USB Hotplugging callbacks with python on Windows
是否可以编写 python 脚本,以便在 ZAEA234289CE3AA9B4ECDA 上添加或删除 USB 设备时调用 function?
libusb
(以及相应的 python 模块,例如libusb1
)似乎是最流行的解决方案,但它在 Windows 中缺乏热插拔回调注册支持。 自 2015 年以来,已为此提出功能请求,但仍未实施。
我已经看到一些黑客在一段时间内查询 Windows 的 usb 设备,对当前设备列表与之前的设备列表进行比较,并将其用作替代方案。 由于我的应用程序的性质,这种 hack 将是一个巨大的安全风险,并且不是一个有效的解决方案。 我需要对 usb 热插拔事件进行实际回调注册。
虽然不太理想,但如果有必要,我愿意在 C 或 C++ 中编写一些东西,然后编写一个 python 绑定到该代码。
当 usb 设备在 ZAEA23489CE3AA9B640EZ3EB4B2 上连接或断开时,是否可以调用 python function?
是的,您可以使用 python 中的 ctypes 来注册WM_DEVICECHANGE
消息的回调。
I was successfully able to add register callback functions to usb hotplug events in both linux (using the libusb1
python module) and windows (using the ctypes
python module). 大部分相关的 windows 代码可以在这里找到:
这主要基于在这些链接中找到的代码:
import win32api, win32con, win32gui
from ctypes import *
#
# Device change events (WM_DEVICECHANGE wParam)
#
DBT_DEVICEARRIVAL = 0x8000
DBT_DEVICEQUERYREMOVE = 0x8001
DBT_DEVICEQUERYREMOVEFAILED = 0x8002
DBT_DEVICEMOVEPENDING = 0x8003
DBT_DEVICEREMOVECOMPLETE = 0x8004
DBT_DEVICETYPESSPECIFIC = 0x8005
DBT_CONFIGCHANGED = 0x0018
#
# type of device in DEV_BROADCAST_HDR
#
DBT_DEVTYP_OEM = 0x00000000
DBT_DEVTYP_DEVNODE = 0x00000001
DBT_DEVTYP_VOLUME = 0x00000002
DBT_DEVTYPE_PORT = 0x00000003
DBT_DEVTYPE_NET = 0x00000004
#
# media types in DBT_DEVTYP_VOLUME
#
DBTF_MEDIA = 0x0001
DBTF_NET = 0x0002
WORD = c_ushort
DWORD = c_ulong
class DEV_BROADCAST_HDR(Structure):
_fields_ = [
("dbch_size", DWORD),
("dbch_devicetype", DWORD),
("dbch_reserved", DWORD)
]
class DEV_BROADCAST_VOLUME(Structure):
_fields_ = [
("dbcv_size", DWORD),
("dbcv_devicetype", DWORD),
("dbcv_reserved", DWORD),
("dbcv_unitmask", DWORD),
("dbcv_flags", WORD)
]
def drive_from_mask(mask):
n_drive = 0
while 1:
if (mask & (2 ** n_drive)):
return n_drive
else:
n_drive += 1
class Notification:
def __init__(self):
message_map = {
win32con.WM_DEVICECHANGE: self.onDeviceChange
}
wc = win32gui.WNDCLASS()
hinst = wc.hInstance = win32api.GetModuleHandle(None)
wc.lpszClassName = "DeviceChangeDemo"
wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW
wc.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW)
wc.hbrBackground = win32con.COLOR_WINDOW
wc.lpfnWndProc = message_map
classAtom = win32gui.RegisterClass(wc)
style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
self.hwnd = win32gui.CreateWindow(
classAtom,
"Device Change Demo",
style,
0, 0,
win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT,
0, 0,
hinst, None
)
def onDeviceChange(self, hwnd, msg, wparam, lparam):
#
# WM_DEVICECHANGE:
# wParam - type of change: arrival, removal etc.
# lParam - what's changed?
# if it's a volume then...
# lParam - what's changed more exactly
#
dev_broadcast_hdr = DEV_BROADCAST_HDR.from_address(lparam)
if wparam == DBT_DEVICEARRIVAL:
print("Something's arrived")
if dev_broadcast_hdr.dbch_devicetype == DBT_DEVTYP_VOLUME:
print("It's a volume!")
dev_broadcast_volume = DEV_BROADCAST_VOLUME.from_address(lparam)
if dev_broadcast_volume.dbcv_flags & DBTF_MEDIA:
print("with some media")
drive_letter = drive_from_mask(dev_broadcast_volume.dbcv_unitmask)
print("in drive", chr(ord("A") + drive_letter))
return 1
if __name__ == '__main__':
w = Notification()
win32gui.PumpMessages()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.