python检测usb插拔,在Windows上使用python进行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 (and corresponding python modules such as libusb1) appears to be the most popular solution, but it lacks hotplugging callback registration support in Windows. A feature request has been open for this since 2015, and it's still not implemented.

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.

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

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

解决方案

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

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:

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()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值