网上基于QT c++, windows下检测usb热插拨的案例很多,python的很少,现在提供基于pyqt5的代码如下:
特别注意pyqt5 不再使用pyqt4中的winEvent而是采用nativeEvent
import sys
import typing
import ctypes
from ctypes import wintypes
import win32con
from PyQt5.QtCore import pyqtBoundSignal, pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget
user32 = ctypes.windll.user32
RegisterDeviceNotification = user32.RegisterDeviceNotificationW
UnregisterDeviceNotification = user32.UnregisterDeviceNotification
class GUID(ctypes.Structure):
_pack_ = 1
_fields_ = [
("Data1", ctypes.c_ulong),
("Data2", ctypes.c_ushort),
("Data3", ctypes.c_ushort),
("Data4", ctypes.c_ubyte * 8)
]
class DEV_BROADCAST_DEVICEINTERFACE(ctypes.Structure):
_pack_ = 1
_fields_ = [
("dbcc_size", wintypes.DWORD),
("dbcc_devicetype", wintypes.DWORD),
("dbcc_reserved", wintypes.DWORD),
("dbcc_classguid", GUID),
("dbcc_name", ctypes.c_wchar * 512)
]
class DEV_BROADCAST_PORT(ctypes.Structure):
_pack_ = 1
_fields_ = [
("dbcp_size", wintypes.DWORD),
("dbcp_devicetype", wintypes.DWORD),
("dbcp_reserved", wintypes.DWORD),
("dbcp_name", ctypes.c_wchar * 512)
]
@property
def dbcpName(self) -> str:
return str(self.dbcp_name)
@property
def dbcpDeviceType(self):
return self.dbcp_devicetype
class DEV_BROADCAST_HDR(ctypes.Structure):
_fields_ = [
("dbch_size", wintypes.DWORD),
("dbch_devicetype", wintypes.DWORD),
("dbch_reserved", wintypes.DWORD)
]
GUID_DEVCLASS_PORTS = \
GUID(0x4d36e967, 0xE325, 0x11CE, (ctypes.c_ubyte * 8)(0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18))
GUID_DEVINTERFACE_USB_DEVICE = \
GUID(0xA5DCBF10, 0x6530, 0x11D2, (ctypes.c_ubyte * 8)(0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED))
EVENT_TYPE_GENERIC = 'windows_generic_MSG'
class UsbSerialPlugMonitor(QWidget):
sigPlugEvent: pyqtBoundSignal = pyqtSignal(str, bool)
def __init__(self, parent=None):
super().__init__(parent)
self.hNotify = win32con.NULL
def start(self):
dbh = DEV_BROADCAST_DEVICEINTERFACE()
dbh.dbcc_size = ctypes.sizeof(DEV_BROADCAST_DEVICEINTERFACE)
print(dbh.dbcc_size)
dbh.dbcc_devicetype = win32con.DBT_DEVTYP_DEVICEINTERFACE
dbh.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE
self.hNotify = RegisterDeviceNotification(int(self.winId()),
ctypes.byref(dbh),
win32con.DEVICE_NOTIFY_WINDOW_HANDLE)
if self.hNotify == win32con.NULL:
print(ctypes.FormatError(), int(self.winId()))
print('RegisterDeviceNotification failed')
def stop(self):
if self.hNotify != win32con.NULL:
print('UnRegisterDeviceNotification')
UnregisterDeviceNotification(self.hNotify)
else:
print('the notify handler is NULL')
def nativeEvent(self, eventType, message) -> typing.Tuple[bool, int]:
if eventType == EVENT_TYPE_GENERIC:
msg: wintypes.MSG = wintypes.MSG.from_address(message.__int__())
if msg.message == win32con.WM_DEVICECHANGE:
if msg.wParam == win32con.DBT_DEVICEARRIVAL:
hdr: DEV_BROADCAST_HDR = DEV_BROADCAST_HDR.from_address(msg.lParam)
if hdr.dbch_devicetype == win32con.DBT_DEVTYP_PORT:
d: DEV_BROADCAST_PORT = DEV_BROADCAST_PORT.from_address(msg.lParam)
print(d.dbcpDeviceType)
print(d.dbcpName)
print('device in')
self.sigPlugEvent.emit(d.dbcpName, True)
elif hdr.dbch_devicetype == win32con.DBT_DEVTYP_DEVICEINTERFACE:
d: DEV_BROADCAST_DEVICEINTERFACE = DEV_BROADCAST_DEVICEINTERFACE.from_address(msg.lParam)
print(d.dbcc_devicetype)
print(d.dbcc_name)
elif msg.wParam == win32con.DBT_DEVICEREMOVECOMPLETE:
hdr: DEV_BROADCAST_HDR = DEV_BROADCAST_HDR.from_address(msg.lParam)
if hdr.dbch_devicetype == win32con.DBT_DEVTYP_PORT:
d: DEV_BROADCAST_PORT = DEV_BROADCAST_PORT.from_address(msg.lParam)
print(d.dbcp_devicetype)
print(d.dbcpName)
print('device remove')
self.sigPlugEvent.emit(d.dbcpName, False)
elif hdr.dbch_devicetype == win32con.DBT_DEVTYP_DEVICEINTERFACE:
d: DEV_BROADCAST_DEVICEINTERFACE = DEV_BROADCAST_DEVICEINTERFACE.from_address(msg.lParam)
print(d.dbcc_devicetype)
print(d.dbcc_name)
return super(UsbSerialPlugMonitor, self).nativeEvent(eventType, message)
def usbPlugEvent(portName: str, isIn: bool):
if isIn is True:
print(portName + 'plugIn')
else:
print(portName + 'plugOut')
if __name__ == '__main__':
app = QApplication(sys.argv)
usbMonitor = UsbSerialPlugMonitor()
usbMonitor.sigPlugEvent.connect(usbPlugEvent)
usbMonitor.start()
sys.exit(app.exec())