pyqt5 usb 热插拔检测

网上基于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())

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值