在Windows上使用python进行USB热插拔回调 [英] USB Hotplugging callbacks with python on Windows

查看:1087
本文介绍了在Windows上使用python进行USB热插拔回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以编写python脚本,以便在Windows上添加或删除USB设备时调用该函数?

Is it possible to write a python script such that a function is called whenever a USB device is added or removed on Windows?

libusb (以及相应的python模块,例如功能请求,但仍未实现.

我已经看到一些黑客以一定的间隔查询Windows的USB设备,对当前设备列表与以前的设备列表进行比较,并将其用作替代方法.由于我的应用程序的性质,这种黑客行为会带来巨大的安全风险,并且不是有效的解决方案.我需要对USB热插拔事件进行 actual 回调注册.

I've seen some hacks query Windows' usb devices at some interval, do a diff of the current list of devices from the previous list of devices, and use this as an alternative. Due to the nature of my application, this hack would be a huge security risk and is not a valid solution. I need actual callback registration on usb hotplug events.

尽管不太理想,但我愿意写点东西使用C或C ++ ,然后根据需要编写与该代码的python绑定.

Though less ideal, I'm open to writing something in C or C++ and then writing a python binding to that code, if necessary.

在Windows上连接或断开USB设备时是否可以调用python函数?

Is it possible to have a python function called when a usb device is connected or disconnected on Windows?

推荐答案

是的,您可以在python中使用ctypes为WM_DEVICECHANGE消息注册回调.

Yes, you can use ctypes in python to register a callback for WM_DEVICECHANGE messages.

我能够在Linux(使用libusb1 python模块)和Windows(使用ctypes python模块)中成功向USB热插拔事件添加注册回调函数.大量相关的Windows代码可以在这里找到:

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). The bulk of the relevant windows code can be found here:

主要基于以下链接中找到的代码:

Which is largely based on the code found at these links:

  • http://timgolden.me.uk/python/win32_how_do_i/detect-device-insertion.html
  • Detect media insertion on Windows in Python
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()

这篇关于在Windows上使用python进行USB热插拔回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆